From 51f69f32d00301d9b58094208ba775daee55cbc2 Mon Sep 17 00:00:00 2001 From: "yihao.dai" Date: Tue, 16 Sep 2025 16:32:01 +0800 Subject: [PATCH] feat: Add CDC support (#44124) This PR implements a new CDC service for Milvus 2.6, providing log-based cross-cluster replication. issue: https://github.com/milvus-io/milvus/issues/44123 --------- Signed-off-by: bigsheeper Signed-off-by: chyezh Co-authored-by: chyezh --- Makefile | 7 + client/go.mod | 6 +- client/go.sum | 4 +- .../milvusclient/mock_milvus_server_test.go | 164 + client/milvusclient/replicate.go | 57 + client/milvusclient/replicate_builder.go | 113 + client/milvusclient/replicate_example_test.go | 116 + cmd/components/cdc.go | 44 + cmd/milvus/util.go | 4 + cmd/roles/roles.go | 23 +- go.mod | 7 +- go.sum | 4 - internal/.mockery.yaml | 3 + internal/cdc/.mockery.yaml | 24 + internal/cdc/cluster/cluster_client.go | 51 + internal/cdc/cluster/milvus_client.go | 34 + internal/cdc/cluster/mock_cluster_client.go | 97 + internal/cdc/cluster/mock_milvus_client.go | 233 ++ internal/cdc/controller/controller.go | 24 + .../controllerimpl/controller_impl.go | 83 + .../controllerimpl/controller_impl_test.go | 83 + internal/cdc/controller/mock_controller.go | 96 + .../mock_replicate_manager_client.go | 68 + .../replication/replicate_manager_client.go | 25 + .../replicatemanager/channel_replicator.go | 237 ++ .../channel_replicator_test.go | 96 + .../mock_channel_replicator.go | 144 + .../replicatemanager/replicate_manager.go | 64 + .../replicate_manager_test.go | 88 + .../replication/replicatestream/metrics.go | 121 + .../mock_replicate_stream_client.go | 113 + .../replication/replicatestream/msg_queue.go | 211 ++ .../replicatestream/msg_queue_test.go | 287 ++ .../replicate_stream_client.go | 38 + .../replicate_stream_client_impl.go | 293 ++ .../replicate_stream_client_impl_test.go | 322 ++ internal/cdc/resource/resource.go | 143 + internal/cdc/resource/test_utility.go | 37 + internal/cdc/server.go | 55 + .../datacoord/session/mock_node_manager.go | 3 +- internal/distributed/cdc/service.go | 194 + internal/distributed/proxy/service.go | 15 + internal/distributed/streaming/append.go | 6 + .../streaming/internal/errs/error.go | 1 + .../streaming/internal/producer/producer.go | 3 + .../streaming/msgstream_adaptor.go | 2 +- .../streaming/replicate_service.go | 149 + .../streaming/replicate_service_test.go | 124 + internal/distributed/streaming/streaming.go | 33 +- .../distributed/streaming/streaming_test.go | 51 +- .../distributed/streaming/test_streaming.go | 37 + internal/distributed/streaming/wal.go | 14 +- internal/metastore/catalog.go | 21 + .../metastore/kv/streamingcoord/constant.go | 4 + .../metastore/kv/streamingcoord/kv_catalog.go | 78 + .../kv/streamingcoord/kv_catalog_test.go | 113 + .../metastore/mocks/mock_rootcoord_catalog.go | 152 - .../mock_streaming/mock_ReplicateService.go | 269 ++ .../mock_streaming/mock_WALAccesser.go | 92 +- .../mock_metastore/mock_ReplicationCatalog.go | 144 + .../mock_StreamingCoordCataLog.go | 212 ++ .../mock_client/mock_AssignmentService.go | 112 +- .../server/mock_balancer/mock_Balancer.go | 120 + .../mock_broadcaster/mock_Broadcaster.go | 225 ++ .../client/mock_handler/mock_HandlerClient.go | 61 + .../server/mock_wal/mock_OpenerBuilder.go | 16 +- .../streamingnode/server/mock_wal/mock_WAL.go | 12 +- internal/proxy/impl.go | 93 +- internal/proxy/proxy.go | 5 - .../replicate/replicate_stream_server.go | 159 + .../replicate/replicate_stream_server_test.go | 237 ++ internal/querynodev2/server.go | 4 +- internal/querynodev2/services_test.go | 7 +- .../client/assignment/assignment_impl.go | 28 + .../client/assignment/assignment_test.go | 3 + .../client/assignment/discoverer.go | 7 + .../client/assignment/watcher.go | 19 +- .../client/broadcast/broadcast_impl.go | 6 +- .../client/broadcast/broadcast_test.go | 7 +- internal/streamingcoord/client/client.go | 11 +- .../server/balancer/balancer.go | 7 + .../server/balancer/balancer_impl.go | 26 + .../server/balancer/balancer_test.go | 2 + .../server/balancer/channel/manager.go | 95 +- .../server/balancer/channel/manager_test.go | 3 + .../server/balancer/channel/pchannel_view.go | 2 +- .../balancer/channel/replicate_config.go | 117 + .../balancer/channel/replicate_config_test.go | 129 + .../server/service/assignment.go | 95 +- .../server/service/broadcast.go | 9 +- .../server/service/broadcast_test.go | 46 + .../discover/discover_grpc_server_helper.go | 5 +- .../streamingcoord/server/service_test.go | 3 + .../client/handler/consumer/consumer_impl.go | 2 +- .../client/handler/consumer/consumer_test.go | 4 +- .../client/handler/handler_client.go | 4 + .../client/handler/handler_client_impl.go | 12 + .../client/handler/producer/producer_impl.go | 5 +- .../client/handler/producer/producer_test.go | 7 +- .../server/flusher/flusherimpl/util.go | 2 +- .../server/flusher/flusherimpl/wal_flusher.go | 2 +- .../flusher/flusherimpl/wal_flusher_test.go | 10 +- internal/streamingnode/server/server.go | 5 - .../streamingnode/server/service/handler.go | 7 + .../handler/consumer/consume_server.go | 2 +- .../handler/consumer/consume_server_test.go | 8 +- .../handler/producer/produce_server.go | 2 +- .../handler/producer/produce_server_test.go | 9 +- .../server/wal/adaptor/builder.go | 3 +- .../server/wal/adaptor/ro_wal_adaptor.go | 2 +- .../server/wal/adaptor/wal_test.go | 2 +- internal/streamingnode/server/wal/builder.go | 3 +- .../interceptors/chain_interceptor_test.go | 2 +- .../server/wal/metricsutil/wal_write.go | 9 +- .../server/wal/recovery/checkpoint.go | 49 - .../server/wal/recovery/checkpoint_test.go | 39 - .../server/wal/recovery/recovery_persisted.go | 10 +- .../wal/recovery/recovery_persisted_test.go | 11 +- .../server/wal/recovery/recovery_storage.go | 6 +- .../wal/recovery/recovery_storage_impl.go | 2 +- .../wal/recovery/recovery_storage_test.go | 8 +- .../server/wal/registry/registry.go | 3 +- .../server/wal/utility/checkpoint.go | 116 + .../server/wal/utility/checkpoint_test.go | 62 + internal/streamingnode/server/wal/wal.go | 8 +- .../server/walmanager/manager_impl.go | 2 +- .../service/contextutil/cluster_id.go | 31 + .../service/contextutil/cluster_id_test.go | 46 + .../service/contextutil/create_producer.go | 4 +- .../streamingutil/status/streaming_error.go | 16 +- .../util/streamingutil/util/wal_selector.go | 43 +- .../streamingutil/util/wal_selector_test.go | 39 +- pkg/go.mod | 2 +- pkg/go.sum | 4 +- pkg/metrics/cdc_metrics.go | 128 + ...k_StreamingCoordAssignmentServiceClient.go | 74 + .../mock_StreamingNodeHandlerServiceClient.go | 74 + .../mock_walimpls/mock_OpenerBuilderImpls.go | 16 +- .../streaming/mock_walimpls/mock_WALImpls.go | 12 +- .../mock_BroadcastMutableMessage.go | 47 + .../mock_message/mock_ImmutableMessage.go | 75 +- .../mock_message/mock_ImmutableTxnMessage.go | 75 +- .../util/mock_message/mock_MessageID.go | 61 +- .../util/mock_message/mock_MutableMessage.go | 47 + pkg/proto/messages.proto | 40 +- pkg/proto/messagespb/messages.pb.go | 1154 +++--- pkg/proto/streaming.proto | 94 +- pkg/proto/streamingpb/streaming.pb.go | 3154 ++++++++++------- pkg/proto/streamingpb/streaming_grpc.pb.go | 109 +- .../util/message/adaptor/message_id.go | 20 +- pkg/streaming/util/message/builder.go | 56 +- pkg/streaming/util/message/builder_test.go | 27 + .../util/message/codegen/reflect_info.json | 10 + .../util/message/marshal_log_object.go | 7 + pkg/streaming/util/message/message.go | 20 +- pkg/streaming/util/message/message_id.go | 30 +- pkg/streaming/util/message/message_id_test.go | 18 +- pkg/streaming/util/message/message_impl.go | 62 +- pkg/streaming/util/message/message_test.go | 19 + pkg/streaming/util/message/message_type.go | 6 + pkg/streaming/util/message/properties.go | 1 + pkg/streaming/util/message/reflect_info.go | 240 +- .../util/message/specialized_message.go | 28 +- pkg/streaming/util/message/utils.go | 9 + pkg/streaming/util/message/wal_name.go | 55 + pkg/streaming/util/options/deliver.go | 8 +- pkg/streaming/util/options/deliver_test.go | 3 +- pkg/streaming/util/types/acked_result.go | 68 + pkg/streaming/util/types/acked_result_test.go | 95 + pkg/streaming/util/types/responses.go | 5 +- pkg/streaming/util/types/responses_test.go | 3 +- pkg/streaming/util/types/streaming_node.go | 8 +- pkg/streaming/walimpls/builder.go | 4 +- pkg/streaming/walimpls/impls/kafka/builder.go | 10 +- .../walimpls/impls/kafka/kafka_test.go | 8 +- .../walimpls/impls/kafka/message_id.go | 13 +- .../walimpls/impls/kafka/message_id_test.go | 2 +- pkg/streaming/walimpls/impls/kafka/wal.go | 4 +- .../walimpls/impls/pulsar/builder.go | 10 +- .../walimpls/impls/pulsar/message_id.go | 12 +- .../walimpls/impls/pulsar/message_id_test.go | 2 +- .../walimpls/impls/pulsar/pulsar_test.go | 11 +- pkg/streaming/walimpls/impls/pulsar/wal.go | 4 +- pkg/streaming/walimpls/impls/rmq/builder.go | 10 +- .../walimpls/impls/rmq/message_id.go | 13 +- .../walimpls/impls/rmq/message_id_test.go | 2 +- pkg/streaming/walimpls/impls/rmq/rmq_test.go | 10 +- pkg/streaming/walimpls/impls/rmq/wal.go | 4 +- .../walimpls/impls/walimplstest/builder.go | 10 +- .../walimpls/impls/walimplstest/message_id.go | 13 +- .../walimpls/impls/walimplstest/wal.go | 4 +- pkg/streaming/walimpls/impls/wp/builder.go | 10 +- pkg/streaming/walimpls/impls/wp/message_id.go | 12 +- .../walimpls/impls/wp/message_id_test.go | 2 +- pkg/streaming/walimpls/impls/wp/wal.go | 4 +- pkg/streaming/walimpls/impls/wp/wp_test.go | 10 +- pkg/streaming/walimpls/registry/registry.go | 9 +- pkg/streaming/walimpls/registry/wal_test.go | 10 +- pkg/streaming/walimpls/wal.go | 2 +- pkg/util/replicateutil/config_helper.go | 214 ++ pkg/util/replicateutil/config_helper_test.go | 436 +++ pkg/util/replicateutil/config_validator.go | 243 ++ .../replicateutil/config_validator_test.go | 717 ++++ pkg/util/replicateutil/util.go | 43 + pkg/util/typeutil/type.go | 3 + scripts/run_go_unittest.sh | 8 + scripts/start_cluster.sh | 3 + scripts/start_standalone.sh | 3 + tests/go_client/go.mod | 2 +- tests/go_client/go.sum | 4 +- 210 files changed, 12883 insertions(+), 2566 deletions(-) create mode 100644 client/milvusclient/replicate.go create mode 100644 client/milvusclient/replicate_builder.go create mode 100644 client/milvusclient/replicate_example_test.go create mode 100644 cmd/components/cdc.go create mode 100644 internal/cdc/.mockery.yaml create mode 100644 internal/cdc/cluster/cluster_client.go create mode 100644 internal/cdc/cluster/milvus_client.go create mode 100644 internal/cdc/cluster/mock_cluster_client.go create mode 100644 internal/cdc/cluster/mock_milvus_client.go create mode 100644 internal/cdc/controller/controller.go create mode 100644 internal/cdc/controller/controllerimpl/controller_impl.go create mode 100644 internal/cdc/controller/controllerimpl/controller_impl_test.go create mode 100644 internal/cdc/controller/mock_controller.go create mode 100644 internal/cdc/replication/mock_replicate_manager_client.go create mode 100644 internal/cdc/replication/replicate_manager_client.go create mode 100644 internal/cdc/replication/replicatemanager/channel_replicator.go create mode 100644 internal/cdc/replication/replicatemanager/channel_replicator_test.go create mode 100644 internal/cdc/replication/replicatemanager/mock_channel_replicator.go create mode 100644 internal/cdc/replication/replicatemanager/replicate_manager.go create mode 100644 internal/cdc/replication/replicatemanager/replicate_manager_test.go create mode 100644 internal/cdc/replication/replicatestream/metrics.go create mode 100644 internal/cdc/replication/replicatestream/mock_replicate_stream_client.go create mode 100644 internal/cdc/replication/replicatestream/msg_queue.go create mode 100644 internal/cdc/replication/replicatestream/msg_queue_test.go create mode 100644 internal/cdc/replication/replicatestream/replicate_stream_client.go create mode 100644 internal/cdc/replication/replicatestream/replicate_stream_client_impl.go create mode 100644 internal/cdc/replication/replicatestream/replicate_stream_client_impl_test.go create mode 100644 internal/cdc/resource/resource.go create mode 100644 internal/cdc/resource/test_utility.go create mode 100644 internal/cdc/server.go create mode 100644 internal/distributed/cdc/service.go create mode 100644 internal/distributed/streaming/replicate_service.go create mode 100644 internal/distributed/streaming/replicate_service_test.go create mode 100644 internal/mocks/distributed/mock_streaming/mock_ReplicateService.go create mode 100644 internal/mocks/mock_metastore/mock_ReplicationCatalog.go create mode 100644 internal/mocks/streamingcoord/server/mock_broadcaster/mock_Broadcaster.go create mode 100644 internal/proxy/replicate/replicate_stream_server.go create mode 100644 internal/proxy/replicate/replicate_stream_server_test.go create mode 100644 internal/streamingcoord/server/balancer/channel/replicate_config.go create mode 100644 internal/streamingcoord/server/balancer/channel/replicate_config_test.go create mode 100644 internal/streamingcoord/server/service/broadcast_test.go delete mode 100644 internal/streamingnode/server/wal/recovery/checkpoint.go delete mode 100644 internal/streamingnode/server/wal/recovery/checkpoint_test.go create mode 100644 internal/streamingnode/server/wal/utility/checkpoint.go create mode 100644 internal/streamingnode/server/wal/utility/checkpoint_test.go create mode 100644 internal/util/streamingutil/service/contextutil/cluster_id.go create mode 100644 internal/util/streamingutil/service/contextutil/cluster_id_test.go create mode 100644 pkg/metrics/cdc_metrics.go create mode 100644 pkg/streaming/util/message/wal_name.go create mode 100644 pkg/streaming/util/types/acked_result.go create mode 100644 pkg/streaming/util/types/acked_result_test.go create mode 100644 pkg/util/replicateutil/config_helper.go create mode 100644 pkg/util/replicateutil/config_helper_test.go create mode 100644 pkg/util/replicateutil/config_validator.go create mode 100644 pkg/util/replicateutil/config_validator_test.go create mode 100644 pkg/util/replicateutil/util.go diff --git a/Makefile b/Makefile index 614c900646..0f6eae74bc 100644 --- a/Makefile +++ b/Makefile @@ -361,6 +361,10 @@ test-mixcoord: @echo "Running go unittests..." @(env bash $(PWD)/scripts/run_go_unittest.sh -t mixcoord) +test-cdc: + @echo "Running cdc unittests..." + @(env bash $(PWD)/scripts/run_go_unittest.sh -t cdc) + test-go: build-cpp-with-unittest @echo "Running go unittests..." @(env bash $(PWD)/scripts/run_go_unittest.sh) @@ -536,6 +540,9 @@ generate-mockery-pkg: generate-mockery-internal: getdeps $(INSTALL_PATH)/mockery --config $(PWD)/internal/.mockery.yaml +generate-mockery-cdc: getdeps + $(INSTALL_PATH)/mockery --config $(PWD)/internal/cdc/.mockery.yaml + generate-mockery: generate-mockery-types generate-mockery-kv generate-mockery-rootcoord generate-mockery-proxy generate-mockery-querycoord generate-mockery-querynode generate-mockery-datacoord generate-mockery-pkg generate-mockery-internal generate-yaml: milvus-tools diff --git a/client/go.mod b/client/go.mod index b43315c3c4..154c41ab19 100644 --- a/client/go.mod +++ b/client/go.mod @@ -6,15 +6,13 @@ require ( github.com/blang/semver/v4 v4.0.0 github.com/cockroachdb/errors v1.9.1 github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 - github.com/milvus-io/milvus-proto/go-api/v2 v2.6.1 + github.com/milvus-io/milvus-proto/go-api/v2 v2.6.2-0.20250901025546-3cddc9bb1357 github.com/milvus-io/milvus/pkg/v2 v2.0.0-20250319085209-5a6b4e56d59e github.com/quasilyte/go-ruleguard/dsl v0.3.22 github.com/samber/lo v1.27.0 github.com/stretchr/testify v1.10.0 github.com/tidwall/gjson v1.17.1 - go.opentelemetry.io/otel v1.28.0 go.uber.org/atomic v1.11.0 - golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 google.golang.org/grpc v1.65.0 google.golang.org/protobuf v1.34.2 ) @@ -89,6 +87,7 @@ require ( go.etcd.io/etcd/raft/v3 v3.5.5 // indirect go.etcd.io/etcd/server/v3 v3.5.5 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect + go.opentelemetry.io/otel v1.28.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.20.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.20.0 // indirect go.opentelemetry.io/otel/metric v1.28.0 // indirect @@ -99,6 +98,7 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect golang.org/x/crypto v0.36.0 // indirect + golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect golang.org/x/net v0.38.0 // indirect golang.org/x/sync v0.12.0 // indirect golang.org/x/sys v0.31.0 // indirect diff --git a/client/go.sum b/client/go.sum index 5db7525978..60089f0997 100644 --- a/client/go.sum +++ b/client/go.sum @@ -318,8 +318,8 @@ github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfr github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8= github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/milvus-io/milvus-proto/go-api/v2 v2.6.1 h1:NLoSWXvlJD8t91G3CUsooXqYnm5nfsBngztQYYT58V0= -github.com/milvus-io/milvus-proto/go-api/v2 v2.6.1/go.mod h1:/6UT4zZl6awVeXLeE7UGDWZvXj3IWkRsh3mqsn0DiAs= +github.com/milvus-io/milvus-proto/go-api/v2 v2.6.2-0.20250901025546-3cddc9bb1357 h1:OYM9ylL42FTVL5kAHOZtsOPqzXq9Pn0/H1YLfXcS/e4= +github.com/milvus-io/milvus-proto/go-api/v2 v2.6.2-0.20250901025546-3cddc9bb1357/go.mod h1:/6UT4zZl6awVeXLeE7UGDWZvXj3IWkRsh3mqsn0DiAs= github.com/milvus-io/milvus/pkg/v2 v2.0.0-20250319085209-5a6b4e56d59e h1:VCr43pG4efacDbM4au70fh8/5hNTftoWzm1iEumvDWM= github.com/milvus-io/milvus/pkg/v2 v2.0.0-20250319085209-5a6b4e56d59e/go.mod h1:37AWzxVs2NS4QUJrkcbeLUwi+4Av0h5mEdjLI62EANU= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= diff --git a/client/milvusclient/mock_milvus_server_test.go b/client/milvusclient/mock_milvus_server_test.go index e16fffb3da..2b9c0254a9 100644 --- a/client/milvusclient/mock_milvus_server_test.go +++ b/client/milvusclient/mock_milvus_server_test.go @@ -1266,6 +1266,52 @@ func (_c *MilvusServiceServer_CreatePrivilegeGroup_Call) RunAndReturn(run func(c return _c } +// CreateReplicateStream provides a mock function with given fields: _a0 +func (_m *MilvusServiceServer) CreateReplicateStream(_a0 milvuspb.MilvusService_CreateReplicateStreamServer) error { + ret := _m.Called(_a0) + + if len(ret) == 0 { + panic("no return value specified for CreateReplicateStream") + } + + var r0 error + if rf, ok := ret.Get(0).(func(milvuspb.MilvusService_CreateReplicateStreamServer) error); ok { + r0 = rf(_a0) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MilvusServiceServer_CreateReplicateStream_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateReplicateStream' +type MilvusServiceServer_CreateReplicateStream_Call struct { + *mock.Call +} + +// CreateReplicateStream is a helper method to define mock.On call +// - _a0 milvuspb.MilvusService_CreateReplicateStreamServer +func (_e *MilvusServiceServer_Expecter) CreateReplicateStream(_a0 interface{}) *MilvusServiceServer_CreateReplicateStream_Call { + return &MilvusServiceServer_CreateReplicateStream_Call{Call: _e.mock.On("CreateReplicateStream", _a0)} +} + +func (_c *MilvusServiceServer_CreateReplicateStream_Call) Run(run func(_a0 milvuspb.MilvusService_CreateReplicateStreamServer)) *MilvusServiceServer_CreateReplicateStream_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(milvuspb.MilvusService_CreateReplicateStreamServer)) + }) + return _c +} + +func (_c *MilvusServiceServer_CreateReplicateStream_Call) Return(_a0 error) *MilvusServiceServer_CreateReplicateStream_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MilvusServiceServer_CreateReplicateStream_Call) RunAndReturn(run func(milvuspb.MilvusService_CreateReplicateStreamServer) error) *MilvusServiceServer_CreateReplicateStream_Call { + _c.Call.Return(run) + return _c +} + // CreateResourceGroup provides a mock function with given fields: _a0, _a1 func (_m *MilvusServiceServer) CreateResourceGroup(_a0 context.Context, _a1 *milvuspb.CreateResourceGroupRequest) (*commonpb.Status, error) { ret := _m.Called(_a0, _a1) @@ -3685,6 +3731,65 @@ func (_c *MilvusServiceServer_GetReplicas_Call) RunAndReturn(run func(context.Co return _c } +// GetReplicateInfo provides a mock function with given fields: _a0, _a1 +func (_m *MilvusServiceServer) GetReplicateInfo(_a0 context.Context, _a1 *milvuspb.GetReplicateInfoRequest) (*milvuspb.GetReplicateInfoResponse, error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for GetReplicateInfo") + } + + var r0 *milvuspb.GetReplicateInfoResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *milvuspb.GetReplicateInfoRequest) (*milvuspb.GetReplicateInfoResponse, error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, *milvuspb.GetReplicateInfoRequest) *milvuspb.GetReplicateInfoResponse); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*milvuspb.GetReplicateInfoResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *milvuspb.GetReplicateInfoRequest) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MilvusServiceServer_GetReplicateInfo_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetReplicateInfo' +type MilvusServiceServer_GetReplicateInfo_Call struct { + *mock.Call +} + +// GetReplicateInfo is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 *milvuspb.GetReplicateInfoRequest +func (_e *MilvusServiceServer_Expecter) GetReplicateInfo(_a0 interface{}, _a1 interface{}) *MilvusServiceServer_GetReplicateInfo_Call { + return &MilvusServiceServer_GetReplicateInfo_Call{Call: _e.mock.On("GetReplicateInfo", _a0, _a1)} +} + +func (_c *MilvusServiceServer_GetReplicateInfo_Call) Run(run func(_a0 context.Context, _a1 *milvuspb.GetReplicateInfoRequest)) *MilvusServiceServer_GetReplicateInfo_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*milvuspb.GetReplicateInfoRequest)) + }) + return _c +} + +func (_c *MilvusServiceServer_GetReplicateInfo_Call) Return(_a0 *milvuspb.GetReplicateInfoResponse, _a1 error) *MilvusServiceServer_GetReplicateInfo_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MilvusServiceServer_GetReplicateInfo_Call) RunAndReturn(run func(context.Context, *milvuspb.GetReplicateInfoRequest) (*milvuspb.GetReplicateInfoResponse, error)) *MilvusServiceServer_GetReplicateInfo_Call { + _c.Call.Return(run) + return _c +} + // GetUserTags provides a mock function with given fields: _a0, _a1 func (_m *MilvusServiceServer) GetUserTags(_a0 context.Context, _a1 *milvuspb.GetUserTagsRequest) (*milvuspb.GetUserTagsResponse, error) { ret := _m.Called(_a0, _a1) @@ -6222,6 +6327,65 @@ func (_c *MilvusServiceServer_UpdateCredential_Call) RunAndReturn(run func(conte return _c } +// UpdateReplicateConfiguration provides a mock function with given fields: _a0, _a1 +func (_m *MilvusServiceServer) UpdateReplicateConfiguration(_a0 context.Context, _a1 *milvuspb.UpdateReplicateConfigurationRequest) (*commonpb.Status, error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for UpdateReplicateConfiguration") + } + + var r0 *commonpb.Status + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *milvuspb.UpdateReplicateConfigurationRequest) (*commonpb.Status, error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, *milvuspb.UpdateReplicateConfigurationRequest) *commonpb.Status); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*commonpb.Status) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *milvuspb.UpdateReplicateConfigurationRequest) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MilvusServiceServer_UpdateReplicateConfiguration_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateReplicateConfiguration' +type MilvusServiceServer_UpdateReplicateConfiguration_Call struct { + *mock.Call +} + +// UpdateReplicateConfiguration is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 *milvuspb.UpdateReplicateConfigurationRequest +func (_e *MilvusServiceServer_Expecter) UpdateReplicateConfiguration(_a0 interface{}, _a1 interface{}) *MilvusServiceServer_UpdateReplicateConfiguration_Call { + return &MilvusServiceServer_UpdateReplicateConfiguration_Call{Call: _e.mock.On("UpdateReplicateConfiguration", _a0, _a1)} +} + +func (_c *MilvusServiceServer_UpdateReplicateConfiguration_Call) Run(run func(_a0 context.Context, _a1 *milvuspb.UpdateReplicateConfigurationRequest)) *MilvusServiceServer_UpdateReplicateConfiguration_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*milvuspb.UpdateReplicateConfigurationRequest)) + }) + return _c +} + +func (_c *MilvusServiceServer_UpdateReplicateConfiguration_Call) Return(_a0 *commonpb.Status, _a1 error) *MilvusServiceServer_UpdateReplicateConfiguration_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MilvusServiceServer_UpdateReplicateConfiguration_Call) RunAndReturn(run func(context.Context, *milvuspb.UpdateReplicateConfigurationRequest) (*commonpb.Status, error)) *MilvusServiceServer_UpdateReplicateConfiguration_Call { + _c.Call.Return(run) + return _c +} + // UpdateResourceGroups provides a mock function with given fields: _a0, _a1 func (_m *MilvusServiceServer) UpdateResourceGroups(_a0 context.Context, _a1 *milvuspb.UpdateResourceGroupsRequest) (*commonpb.Status, error) { ret := _m.Called(_a0, _a1) diff --git a/client/milvusclient/replicate.go b/client/milvusclient/replicate.go new file mode 100644 index 0000000000..d615feed52 --- /dev/null +++ b/client/milvusclient/replicate.go @@ -0,0 +1,57 @@ +package milvusclient + +import ( + "context" + + "github.com/cockroachdb/errors" + "google.golang.org/grpc" + + "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" + "github.com/milvus-io/milvus-proto/go-api/v2/milvuspb" + "github.com/milvus-io/milvus/pkg/v2/util/merr" +) + +// UpdateReplicateConfiguration updates the replicate configuration to the Milvus cluster. +// Use ReplicateConfigurationBuilder to build the configuration. +func (c *Client) UpdateReplicateConfiguration(ctx context.Context, config *commonpb.ReplicateConfiguration, opts ...grpc.CallOption) error { + req := &milvuspb.UpdateReplicateConfigurationRequest{ + ReplicateConfiguration: config, + } + + err := c.callService(func(milvusService milvuspb.MilvusServiceClient) error { + resp, err := milvusService.UpdateReplicateConfiguration(ctx, req, opts...) + return merr.CheckRPCCall(resp, err) + }) + return err +} + +// GetReplicateInfo gets replicate information from the Milvus cluster +func (c *Client) GetReplicateInfo(ctx context.Context, sourceClusterID string, opts ...grpc.CallOption) (*milvuspb.GetReplicateInfoResponse, error) { + req := &milvuspb.GetReplicateInfoRequest{ + SourceClusterId: sourceClusterID, + } + var resp *milvuspb.GetReplicateInfoResponse + err := c.callService(func(milvusService milvuspb.MilvusServiceClient) error { + var err error + resp, err = milvusService.GetReplicateInfo(ctx, req, opts...) + return merr.CheckRPCCall(resp, err) + }) + return resp, err +} + +// CreateReplicateStream creates a replicate stream +func (c *Client) CreateReplicateStream(ctx context.Context, opts ...grpc.CallOption) (milvuspb.MilvusService_CreateReplicateStreamClient, error) { + var streamClient milvuspb.MilvusService_CreateReplicateStreamClient + err := c.callService(func(milvusService milvuspb.MilvusServiceClient) error { + var err error + streamClient, err = milvusService.CreateReplicateStream(ctx, opts...) + if err != nil { + return err + } + if streamClient == nil { + return errors.New("stream client is nil") + } + return nil + }) + return streamClient, err +} diff --git a/client/milvusclient/replicate_builder.go b/client/milvusclient/replicate_builder.go new file mode 100644 index 0000000000..6c7e35c3ed --- /dev/null +++ b/client/milvusclient/replicate_builder.go @@ -0,0 +1,113 @@ +package milvusclient + +import "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" + +// MilvusClusterBuilder defines the interface for building Milvus cluster configuration +type MilvusClusterBuilder interface { + // WithPchannels adds physical channels + WithPchannels(pchannels ...string) MilvusClusterBuilder + + // WithToken sets the authentication token + WithToken(token string) MilvusClusterBuilder + + // WithURI sets the connection URI + WithURI(uri string) MilvusClusterBuilder + + // Build constructs and returns the MilvusCluster object + Build() *commonpb.MilvusCluster +} + +// ReplicateConfigurationBuilder defines the interface for building replicate configuration +type ReplicateConfigurationBuilder interface { + // WithCluster adds a cluster configuration, you can use MilvusClusterBuilder to create a cluster + WithCluster(cluster *commonpb.MilvusCluster) ReplicateConfigurationBuilder + + // WithTopology adds a cross-cluster topology configuration + WithTopology(sourceClusterID, targetClusterID string) ReplicateConfigurationBuilder + + // Build constructs and returns the configuration object + Build() *commonpb.ReplicateConfiguration +} + +// NewMilvusClusterBuilder creates a new Milvus cluster builder +func NewMilvusClusterBuilder(clusterID string) MilvusClusterBuilder { + return newMilvusClusterBuilder(clusterID) +} + +// NewReplicateConfigurationBuilder creates a new replicate configuration builder +func NewReplicateConfigurationBuilder() ReplicateConfigurationBuilder { + return newReplicateConfigurationBuilder() +} + +type milvusClusterBuilder struct { + clusterID string + uri string + token string + pchannels []string +} + +func newMilvusClusterBuilder(clusterID string) MilvusClusterBuilder { + return &milvusClusterBuilder{ + clusterID: clusterID, + uri: "localhost:19530", // default URI + token: "", // default empty token + pchannels: []string{}, + } +} + +func (b *milvusClusterBuilder) WithPchannels(pchannels ...string) MilvusClusterBuilder { + b.pchannels = append(b.pchannels, pchannels...) + return b +} + +func (b *milvusClusterBuilder) WithToken(token string) MilvusClusterBuilder { + b.token = token + return b +} + +func (b *milvusClusterBuilder) WithURI(uri string) MilvusClusterBuilder { + b.uri = uri + return b +} + +func (b *milvusClusterBuilder) Build() *commonpb.MilvusCluster { + return &commonpb.MilvusCluster{ + ClusterId: b.clusterID, + ConnectionParam: &commonpb.ConnectionParam{ + Uri: b.uri, + Token: b.token, + }, + Pchannels: b.pchannels, + } +} + +type replicateConfigurationBuilder struct { + config *commonpb.ReplicateConfiguration +} + +func newReplicateConfigurationBuilder() ReplicateConfigurationBuilder { + return &replicateConfigurationBuilder{ + config: &commonpb.ReplicateConfiguration{ + Clusters: []*commonpb.MilvusCluster{}, + CrossClusterTopology: []*commonpb.CrossClusterTopology{}, + }, + } +} + +func (b *replicateConfigurationBuilder) WithCluster(cluster *commonpb.MilvusCluster) ReplicateConfigurationBuilder { + b.config.Clusters = append(b.config.Clusters, cluster) + return b +} + +func (b *replicateConfigurationBuilder) WithTopology(sourceClusterID, targetClusterID string) ReplicateConfigurationBuilder { + topology := &commonpb.CrossClusterTopology{ + SourceClusterId: sourceClusterID, + TargetClusterId: targetClusterID, + } + b.config.CrossClusterTopology = append(b.config.CrossClusterTopology, topology) + return b +} + +func (b *replicateConfigurationBuilder) Build() *commonpb.ReplicateConfiguration { + return b.config +} diff --git a/client/milvusclient/replicate_example_test.go b/client/milvusclient/replicate_example_test.go new file mode 100644 index 0000000000..2f98147b37 --- /dev/null +++ b/client/milvusclient/replicate_example_test.go @@ -0,0 +1,116 @@ +// Licensed to the LF AI & Data foundation under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The 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. + +// nolint +package milvusclient_test + +import ( + "context" + "log" + + "github.com/milvus-io/milvus/client/v2/milvusclient" +) + +const ( + exampleMilvusAddr = `127.0.0.1:19530` +) + +func ExampleClient_UpdateReplicateConfiguration() { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + cli, err := milvusclient.New(ctx, &milvusclient.ClientConfig{ + Address: exampleMilvusAddr, + }) + if err != nil { + log.Fatal(err) + } + + // Use builder pattern to create cluster configuration (chained calls) + sourceCluster := milvusclient.NewMilvusClusterBuilder("source-cluster"). + WithURI("localhost:19530"). + WithToken("source-token"). + WithPchannels("source-channel-1", "source-channel-2"). + Build() + + targetCluster := milvusclient.NewMilvusClusterBuilder("target-cluster"). + WithURI("localhost:19531"). + WithToken("target-token"). + WithPchannels("target-channel-1", "target-channel-2"). + Build() + + // Use builder pattern to build replicate configuration + config := milvusclient.NewReplicateConfigurationBuilder(). + WithCluster(sourceCluster). + WithCluster(targetCluster). + WithTopology("source-cluster", "target-cluster"). + Build() + + // Update replicate configuration + err = cli.UpdateReplicateConfiguration(ctx, config) + if err != nil { + log.Printf("Failed to update replicate configuration: %v", err) + return + } + + log.Println("Replicate configuration updated successfully") +} + +func ExampleClient_GetReplicateInfo() { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + cli, err := milvusclient.New(ctx, &milvusclient.ClientConfig{ + Address: exampleMilvusAddr, + }) + if err != nil { + log.Fatal(err) + } + + // Get replicate information for a specific source cluster + resp, err := cli.GetReplicateInfo(ctx, "source-cluster") + if err != nil { + log.Printf("Failed to get replicate information: %v", err) + return + } + + log.Printf("Replicate information retrieved successfully, checkpoint count: %d", len(resp.GetCheckpoints())) +} + +func ExampleClient_CreateReplicateStream() { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + cli, err := milvusclient.New(ctx, &milvusclient.ClientConfig{ + Address: exampleMilvusAddr, + }) + if err != nil { + log.Fatal(err) + } + + // Create replicate stream + stream, err := cli.CreateReplicateStream(ctx) + if err != nil { + log.Printf("Failed to create replicate stream: %v", err) + return + } + defer stream.CloseSend() + + log.Println("Replicate stream created successfully") + + // Here you can continue to use the stream for data transmission + // For example: stream.Send(&milvuspb.ReplicateMessage{...}) +} diff --git a/cmd/components/cdc.go b/cmd/components/cdc.go new file mode 100644 index 0000000000..4c3bdfb0e8 --- /dev/null +++ b/cmd/components/cdc.go @@ -0,0 +1,44 @@ +// Licensed to the LF AI & Data foundation under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The 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 components + +import ( + "context" + + "github.com/milvus-io/milvus/internal/distributed/cdc" + "github.com/milvus-io/milvus/internal/util/dependency" + "github.com/milvus-io/milvus/pkg/v2/util/typeutil" +) + +type CDC struct { + *cdc.Server +} + +// NewCDC creates a new CDC +func NewCDC(ctx context.Context, factory dependency.Factory) (*CDC, error) { + svr, err := cdc.NewServer(ctx) + if err != nil { + return nil, err + } + return &CDC{ + Server: svr, + }, nil +} + +func (c *CDC) GetName() string { + return typeutil.CDCRole +} diff --git a/cmd/milvus/util.go b/cmd/milvus/util.go index f54c5f84b2..f728ee3a4f 100644 --- a/cmd/milvus/util.go +++ b/cmd/milvus/util.go @@ -147,6 +147,7 @@ func GetMilvusRoles(args []string, flags *flag.FlagSet) *roles.MilvusRoles { role.EnableQueryNode = true role.EnableDataNode = true role.EnableStreamingNode = true + role.EnableCDC = true role.Local = true role.Embedded = serverType == typeutil.EmbeddedRole case typeutil.MixCoordRole: @@ -164,6 +165,9 @@ func GetMilvusRoles(args []string, flags *flag.FlagSet) *roles.MilvusRoles { role.EnableQueryNode = true streamingutil.EnableEmbededQueryNode() } + + case typeutil.CDCRole: + role.EnableCDC = true default: fmt.Fprintf(os.Stderr, "Unknown server type = %s\n%s", serverType, getHelp()) os.Exit(-1) diff --git a/cmd/roles/roles.go b/cmd/roles/roles.go index 937974f000..a3def5a256 100644 --- a/cmd/roles/roles.go +++ b/cmd/roles/roles.go @@ -48,6 +48,7 @@ import ( "github.com/milvus-io/milvus/pkg/v2/log" "github.com/milvus-io/milvus/pkg/v2/metrics" rocksmqimpl "github.com/milvus-io/milvus/pkg/v2/mq/mqimpl/rocksmq/server" + "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" "github.com/milvus-io/milvus/pkg/v2/tracer" "github.com/milvus-io/milvus/pkg/v2/util/etcd" "github.com/milvus-io/milvus/pkg/v2/util/expr" @@ -73,7 +74,7 @@ func init() { // stopRocksmqIfUsed closes the RocksMQ if it is used. func stopRocksmqIfUsed() { - if name := util.MustSelectWALName(); name == util.WALTypeRocksmq { + if name := util.MustSelectWALName(); name == message.WALNameRocksmq { rocksmqimpl.CloseRocksMQ() } } @@ -149,6 +150,7 @@ type MilvusRoles struct { EnableRootCoord bool `env:"ENABLE_ROOT_COORD"` EnableQueryCoord bool `env:"ENABLE_QUERY_COORD"` EnableDataCoord bool `env:"ENABLE_DATA_COORD"` + EnableCDC bool `env:"ENABLE_CDC"` Local bool Alias string Embedded bool @@ -207,6 +209,11 @@ func (mr *MilvusRoles) runDataNode(ctx context.Context, localMsg bool, wg *sync. return runComponent(ctx, localMsg, wg, components.NewDataNode, metrics.RegisterDataNode) } +func (mr *MilvusRoles) runCDC(ctx context.Context, localMsg bool, wg *sync.WaitGroup) component { + wg.Add(1) + return runComponent(ctx, localMsg, wg, components.NewCDC, metrics.RegisterCDC) +} + func (mr *MilvusRoles) setupLogger() { params := paramtable.Get() logConfig := log.Config{ @@ -371,6 +378,7 @@ func (mr *MilvusRoles) Run() { mr.EnableRootCoord, mr.EnableQueryCoord, mr.EnableDataCoord, + mr.EnableCDC, } enableComponents = lo.Filter(enableComponents, func(v bool, _ int) bool { return v @@ -400,7 +408,7 @@ func (mr *MilvusRoles) Run() { componentMap := make(map[string]component) var mixCoord component - var proxy, dataNode, queryNode, streamingNode component + var proxy, dataNode, queryNode, streamingNode, cdc component if (mr.EnableRootCoord && mr.EnableDataCoord && mr.EnableQueryCoord) || mr.EnableMixCoord { paramtable.SetLocalComponentEnabled(typeutil.MixCoordRole) @@ -433,6 +441,12 @@ func (mr *MilvusRoles) Run() { componentMap[typeutil.StreamingNodeRole] = streamingNode } + if mr.EnableCDC { + paramtable.SetLocalComponentEnabled(typeutil.CDCRole) + cdc = mr.runCDC(ctx, local, &wg) + componentMap[typeutil.CDCRole] = cdc + } + wg.Wait() http.RegisterStopComponent(func(role string) error { @@ -503,7 +517,7 @@ func (mr *MilvusRoles) Run() { log.Info("All coordinators have stopped") // stop nodes - nodes := []component{streamingNode, queryNode, dataNode} + nodes := []component{streamingNode, queryNode, dataNode, cdc} stopNodeWG := &sync.WaitGroup{} for _, node := range nodes { if node != nil { @@ -546,5 +560,8 @@ func (mr *MilvusRoles) GetRoles() []string { if mr.EnableDataNode { roles = append(roles, typeutil.DataNodeRole) } + if mr.EnableCDC { + roles = append(roles, typeutil.CDCRole) + } return roles } diff --git a/go.mod b/go.mod index 154f13514d..e9bb1ca093 100644 --- a/go.mod +++ b/go.mod @@ -58,6 +58,7 @@ require ( require ( cloud.google.com/go/storage v1.50.0 github.com/antlr4-go/antlr/v4 v4.13.1 + github.com/apache/pulsar-client-go v0.15.1 github.com/aws/aws-sdk-go-v2 v1.36.3 github.com/aws/aws-sdk-go-v2/config v1.29.9 github.com/aws/aws-sdk-go-v2/credentials v1.17.62 @@ -72,7 +73,8 @@ require ( github.com/hashicorp/golang-lru/v2 v2.0.7 github.com/jolestar/go-commons-pool/v2 v2.1.2 github.com/magiconair/properties v1.8.7 - github.com/milvus-io/milvus/pkg/v2 v2.0.0-00010101000000-000000000000 + github.com/milvus-io/milvus/client/v2 v2.6.0 + github.com/milvus-io/milvus/pkg/v2 v2.5.7 github.com/pkg/errors v0.9.1 github.com/remeh/sizedwaitgroup v1.0.0 github.com/shirou/gopsutil/v4 v4.24.10 @@ -93,6 +95,8 @@ require ( github.com/smartystreets/goconvey v1.7.2 // indirect ) +replace github.com/milvus-io/milvus/client/v2 => ./client + require ( cel.dev/expr v0.19.1 // indirect cloud.google.com/go v0.118.3 // indirect @@ -116,7 +120,6 @@ require ( github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68 // indirect github.com/alibabacloud-go/tea v1.1.8 // indirect github.com/andybalholm/brotli v1.1.0 // indirect - github.com/apache/pulsar-client-go v0.15.1 // indirect github.com/apache/thrift v0.20.0 // indirect github.com/ardielle/ardielle-go v1.5.2 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.7 // indirect diff --git a/go.sum b/go.sum index 1f69a4f346..ebbb46da25 100644 --- a/go.sum +++ b/go.sum @@ -786,10 +786,6 @@ github.com/milvus-io/cgosymbolizer v0.0.0-20250318084424-114f4050c3a6 h1:YHMFI6L github.com/milvus-io/cgosymbolizer v0.0.0-20250318084424-114f4050c3a6/go.mod h1:DvXTE/K/RtHehxU8/GtDs4vFtfw64jJ3PaCnFri8CRg= github.com/milvus-io/gorocksdb v0.0.0-20220624081344-8c5f4212846b h1:TfeY0NxYxZzUfIfYe5qYDBzt4ZYRqzUjTR6CvUzjat8= github.com/milvus-io/gorocksdb v0.0.0-20220624081344-8c5f4212846b/go.mod h1:iwW+9cWfIzzDseEBCCeDSN5SD16Tidvy8cwQ7ZY8Qj4= -github.com/milvus-io/milvus-proto/go-api/v2 v2.6.1 h1:NLoSWXvlJD8t91G3CUsooXqYnm5nfsBngztQYYT58V0= -github.com/milvus-io/milvus-proto/go-api/v2 v2.6.1/go.mod h1:/6UT4zZl6awVeXLeE7UGDWZvXj3IWkRsh3mqsn0DiAs= -github.com/milvus-io/milvus-proto/go-api/v2 v2.6.2-0.20250903074146-fe93017b6822 h1:aLZGg4Hfy37RDTqMXsVAcqv+CqzpRtN13tLfgcGK1nQ= -github.com/milvus-io/milvus-proto/go-api/v2 v2.6.2-0.20250903074146-fe93017b6822/go.mod h1:/6UT4zZl6awVeXLeE7UGDWZvXj3IWkRsh3mqsn0DiAs= github.com/milvus-io/milvus-proto/go-api/v2 v2.6.2-0.20250903080546-f1a74984d9e4 h1:9hoFUhw6wVRGBZFPDNjEaUihvZy5DEOV+SxRIWLEbRM= github.com/milvus-io/milvus-proto/go-api/v2 v2.6.2-0.20250903080546-f1a74984d9e4/go.mod h1:/6UT4zZl6awVeXLeE7UGDWZvXj3IWkRsh3mqsn0DiAs= github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8 h1:AMFGa4R4MiIpspGNG7Z948v4n35fFGB3RR3G/ry4FWs= diff --git a/internal/.mockery.yaml b/internal/.mockery.yaml index 5504fcdf4a..e6e9d1838c 100644 --- a/internal/.mockery.yaml +++ b/internal/.mockery.yaml @@ -9,6 +9,7 @@ packages: github.com/milvus-io/milvus/internal/distributed/streaming: interfaces: WALAccesser: + ReplicateService: Utility: Broadcast: Local: @@ -18,6 +19,7 @@ packages: Balancer: github.com/milvus-io/milvus/internal/streamingcoord/server/broadcaster: interfaces: + Broadcaster: AppendOperator: Watcher: github.com/milvus-io/milvus/internal/streamingcoord/client: @@ -78,6 +80,7 @@ packages: Manager: github.com/milvus-io/milvus/internal/metastore: interfaces: + ReplicationCatalog: StreamingCoordCataLog: StreamingNodeCataLog: github.com/milvus-io/milvus/internal/util/segcore: diff --git a/internal/cdc/.mockery.yaml b/internal/cdc/.mockery.yaml new file mode 100644 index 0000000000..f6db99745f --- /dev/null +++ b/internal/cdc/.mockery.yaml @@ -0,0 +1,24 @@ +quiet: False +with-expecter: True +inpackage: True +filename: "mock_{{.InterfaceNameSnake}}.go" +mockname: "Mock{{.InterfaceName}}" +outpkg: "{{.PackageName}}" +dir: "{{.InterfaceDir}}" +packages: + github.com/milvus-io/milvus/internal/cdc/cluster: + interfaces: + ClusterClient: + MilvusClient: + github.com/milvus-io/milvus/internal/cdc/replication: + interfaces: + ReplicateManagerClient: + github.com/milvus-io/milvus/internal/cdc/replication/replicatestream: + interfaces: + ReplicateStreamClient: + github.com/milvus-io/milvus/internal/cdc/replication/replicatemanager: + interfaces: + ChannelReplicator: + github.com/milvus-io/milvus/internal/cdc/controller: + interfaces: + Controller: diff --git a/internal/cdc/cluster/cluster_client.go b/internal/cdc/cluster/cluster_client.go new file mode 100644 index 0000000000..c5e0a84ca1 --- /dev/null +++ b/internal/cdc/cluster/cluster_client.go @@ -0,0 +1,51 @@ +// Licensed to the LF AI & Data foundation under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The 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 cluster + +import ( + "context" + + "go.uber.org/zap" + + "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" + "github.com/milvus-io/milvus/client/v2/milvusclient" + "github.com/milvus-io/milvus/pkg/v2/log" +) + +type ClusterClient interface { + CreateMilvusClient(ctx context.Context, cluster *commonpb.MilvusCluster) (MilvusClient, error) +} + +var _ ClusterClient = (*clusterClient)(nil) + +type clusterClient struct{} + +func NewClusterClient() ClusterClient { + return &clusterClient{} +} + +func (c *clusterClient) CreateMilvusClient(ctx context.Context, cluster *commonpb.MilvusCluster) (MilvusClient, error) { + cli, err := milvusclient.New(ctx, &milvusclient.ClientConfig{ + Address: cluster.GetConnectionParam().GetUri(), + APIKey: cluster.GetConnectionParam().GetToken(), + }) + if err != nil { + log.Warn("failed to create milvus client", zap.Error(err)) + return nil, err + } + return cli, nil +} diff --git a/internal/cdc/cluster/milvus_client.go b/internal/cdc/cluster/milvus_client.go new file mode 100644 index 0000000000..025ca9c04a --- /dev/null +++ b/internal/cdc/cluster/milvus_client.go @@ -0,0 +1,34 @@ +// Licensed to the LF AI & Data foundation under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The 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 cluster + +import ( + "context" + + "google.golang.org/grpc" + + "github.com/milvus-io/milvus-proto/go-api/v2/milvuspb" +) + +type MilvusClient interface { + // GetReplicateInfo gets the replicate information from the milvus cluster. + GetReplicateInfo(ctx context.Context, sourceClusterID string, opts ...grpc.CallOption) (*milvuspb.GetReplicateInfoResponse, error) + // CreateReplicateStream creates a replicate stream to the milvus cluster. + CreateReplicateStream(ctx context.Context, opts ...grpc.CallOption) (milvuspb.MilvusService_CreateReplicateStreamClient, error) + // Close closes the milvus client. + Close(ctx context.Context) error +} diff --git a/internal/cdc/cluster/mock_cluster_client.go b/internal/cdc/cluster/mock_cluster_client.go new file mode 100644 index 0000000000..11c5b1008a --- /dev/null +++ b/internal/cdc/cluster/mock_cluster_client.go @@ -0,0 +1,97 @@ +// Code generated by mockery v2.53.3. DO NOT EDIT. + +package cluster + +import ( + context "context" + + commonpb "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" + + mock "github.com/stretchr/testify/mock" +) + +// MockClusterClient is an autogenerated mock type for the ClusterClient type +type MockClusterClient struct { + mock.Mock +} + +type MockClusterClient_Expecter struct { + mock *mock.Mock +} + +func (_m *MockClusterClient) EXPECT() *MockClusterClient_Expecter { + return &MockClusterClient_Expecter{mock: &_m.Mock} +} + +// CreateMilvusClient provides a mock function with given fields: ctx, _a1 +func (_m *MockClusterClient) CreateMilvusClient(ctx context.Context, _a1 *commonpb.MilvusCluster) (MilvusClient, error) { + ret := _m.Called(ctx, _a1) + + if len(ret) == 0 { + panic("no return value specified for CreateMilvusClient") + } + + var r0 MilvusClient + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *commonpb.MilvusCluster) (MilvusClient, error)); ok { + return rf(ctx, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, *commonpb.MilvusCluster) MilvusClient); ok { + r0 = rf(ctx, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(MilvusClient) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *commonpb.MilvusCluster) error); ok { + r1 = rf(ctx, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockClusterClient_CreateMilvusClient_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateMilvusClient' +type MockClusterClient_CreateMilvusClient_Call struct { + *mock.Call +} + +// CreateMilvusClient is a helper method to define mock.On call +// - ctx context.Context +// - _a1 *commonpb.MilvusCluster +func (_e *MockClusterClient_Expecter) CreateMilvusClient(ctx interface{}, _a1 interface{}) *MockClusterClient_CreateMilvusClient_Call { + return &MockClusterClient_CreateMilvusClient_Call{Call: _e.mock.On("CreateMilvusClient", ctx, _a1)} +} + +func (_c *MockClusterClient_CreateMilvusClient_Call) Run(run func(ctx context.Context, _a1 *commonpb.MilvusCluster)) *MockClusterClient_CreateMilvusClient_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*commonpb.MilvusCluster)) + }) + return _c +} + +func (_c *MockClusterClient_CreateMilvusClient_Call) Return(_a0 MilvusClient, _a1 error) *MockClusterClient_CreateMilvusClient_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockClusterClient_CreateMilvusClient_Call) RunAndReturn(run func(context.Context, *commonpb.MilvusCluster) (MilvusClient, error)) *MockClusterClient_CreateMilvusClient_Call { + _c.Call.Return(run) + return _c +} + +// NewMockClusterClient creates a new instance of MockClusterClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockClusterClient(t interface { + mock.TestingT + Cleanup(func()) +}) *MockClusterClient { + mock := &MockClusterClient{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/internal/cdc/cluster/mock_milvus_client.go b/internal/cdc/cluster/mock_milvus_client.go new file mode 100644 index 0000000000..36b4ce71d6 --- /dev/null +++ b/internal/cdc/cluster/mock_milvus_client.go @@ -0,0 +1,233 @@ +// Code generated by mockery v2.53.3. DO NOT EDIT. + +package cluster + +import ( + context "context" + + grpc "google.golang.org/grpc" + + milvuspb "github.com/milvus-io/milvus-proto/go-api/v2/milvuspb" + + mock "github.com/stretchr/testify/mock" +) + +// MockMilvusClient is an autogenerated mock type for the MilvusClient type +type MockMilvusClient struct { + mock.Mock +} + +type MockMilvusClient_Expecter struct { + mock *mock.Mock +} + +func (_m *MockMilvusClient) EXPECT() *MockMilvusClient_Expecter { + return &MockMilvusClient_Expecter{mock: &_m.Mock} +} + +// Close provides a mock function with given fields: ctx +func (_m *MockMilvusClient) Close(ctx context.Context) error { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for Close") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context) error); ok { + r0 = rf(ctx) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockMilvusClient_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close' +type MockMilvusClient_Close_Call struct { + *mock.Call +} + +// Close is a helper method to define mock.On call +// - ctx context.Context +func (_e *MockMilvusClient_Expecter) Close(ctx interface{}) *MockMilvusClient_Close_Call { + return &MockMilvusClient_Close_Call{Call: _e.mock.On("Close", ctx)} +} + +func (_c *MockMilvusClient_Close_Call) Run(run func(ctx context.Context)) *MockMilvusClient_Close_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *MockMilvusClient_Close_Call) Return(_a0 error) *MockMilvusClient_Close_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockMilvusClient_Close_Call) RunAndReturn(run func(context.Context) error) *MockMilvusClient_Close_Call { + _c.Call.Return(run) + return _c +} + +// CreateReplicateStream provides a mock function with given fields: ctx, opts +func (_m *MockMilvusClient) CreateReplicateStream(ctx context.Context, opts ...grpc.CallOption) (milvuspb.MilvusService_CreateReplicateStreamClient, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for CreateReplicateStream") + } + + var r0 milvuspb.MilvusService_CreateReplicateStreamClient + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, ...grpc.CallOption) (milvuspb.MilvusService_CreateReplicateStreamClient, error)); ok { + return rf(ctx, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, ...grpc.CallOption) milvuspb.MilvusService_CreateReplicateStreamClient); ok { + r0 = rf(ctx, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(milvuspb.MilvusService_CreateReplicateStreamClient) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, ...grpc.CallOption) error); ok { + r1 = rf(ctx, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockMilvusClient_CreateReplicateStream_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateReplicateStream' +type MockMilvusClient_CreateReplicateStream_Call struct { + *mock.Call +} + +// CreateReplicateStream is a helper method to define mock.On call +// - ctx context.Context +// - opts ...grpc.CallOption +func (_e *MockMilvusClient_Expecter) CreateReplicateStream(ctx interface{}, opts ...interface{}) *MockMilvusClient_CreateReplicateStream_Call { + return &MockMilvusClient_CreateReplicateStream_Call{Call: _e.mock.On("CreateReplicateStream", + append([]interface{}{ctx}, opts...)...)} +} + +func (_c *MockMilvusClient_CreateReplicateStream_Call) Run(run func(ctx context.Context, opts ...grpc.CallOption)) *MockMilvusClient_CreateReplicateStream_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-1) + for i, a := range args[1:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), variadicArgs...) + }) + return _c +} + +func (_c *MockMilvusClient_CreateReplicateStream_Call) Return(_a0 milvuspb.MilvusService_CreateReplicateStreamClient, _a1 error) *MockMilvusClient_CreateReplicateStream_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockMilvusClient_CreateReplicateStream_Call) RunAndReturn(run func(context.Context, ...grpc.CallOption) (milvuspb.MilvusService_CreateReplicateStreamClient, error)) *MockMilvusClient_CreateReplicateStream_Call { + _c.Call.Return(run) + return _c +} + +// GetReplicateInfo provides a mock function with given fields: ctx, sourceClusterID, opts +func (_m *MockMilvusClient) GetReplicateInfo(ctx context.Context, sourceClusterID string, opts ...grpc.CallOption) (*milvuspb.GetReplicateInfoResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, sourceClusterID) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for GetReplicateInfo") + } + + var r0 *milvuspb.GetReplicateInfoResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, ...grpc.CallOption) (*milvuspb.GetReplicateInfoResponse, error)); ok { + return rf(ctx, sourceClusterID, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, string, ...grpc.CallOption) *milvuspb.GetReplicateInfoResponse); ok { + r0 = rf(ctx, sourceClusterID, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*milvuspb.GetReplicateInfoResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string, ...grpc.CallOption) error); ok { + r1 = rf(ctx, sourceClusterID, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockMilvusClient_GetReplicateInfo_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetReplicateInfo' +type MockMilvusClient_GetReplicateInfo_Call struct { + *mock.Call +} + +// GetReplicateInfo is a helper method to define mock.On call +// - ctx context.Context +// - sourceClusterID string +// - opts ...grpc.CallOption +func (_e *MockMilvusClient_Expecter) GetReplicateInfo(ctx interface{}, sourceClusterID interface{}, opts ...interface{}) *MockMilvusClient_GetReplicateInfo_Call { + return &MockMilvusClient_GetReplicateInfo_Call{Call: _e.mock.On("GetReplicateInfo", + append([]interface{}{ctx, sourceClusterID}, opts...)...)} +} + +func (_c *MockMilvusClient_GetReplicateInfo_Call) Run(run func(ctx context.Context, sourceClusterID string, opts ...grpc.CallOption)) *MockMilvusClient_GetReplicateInfo_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(string), variadicArgs...) + }) + return _c +} + +func (_c *MockMilvusClient_GetReplicateInfo_Call) Return(_a0 *milvuspb.GetReplicateInfoResponse, _a1 error) *MockMilvusClient_GetReplicateInfo_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockMilvusClient_GetReplicateInfo_Call) RunAndReturn(run func(context.Context, string, ...grpc.CallOption) (*milvuspb.GetReplicateInfoResponse, error)) *MockMilvusClient_GetReplicateInfo_Call { + _c.Call.Return(run) + return _c +} + +// NewMockMilvusClient creates a new instance of MockMilvusClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockMilvusClient(t interface { + mock.TestingT + Cleanup(func()) +}) *MockMilvusClient { + mock := &MockMilvusClient{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/internal/cdc/controller/controller.go b/internal/cdc/controller/controller.go new file mode 100644 index 0000000000..e3c14a2834 --- /dev/null +++ b/internal/cdc/controller/controller.go @@ -0,0 +1,24 @@ +// Licensed to the LF AI & Data foundation under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The 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 controller + +// Controller controls and schedules the CDC process. +// It will periodically update the replications by the replicate configuration. +type Controller interface { + Start() + Stop() +} diff --git a/internal/cdc/controller/controllerimpl/controller_impl.go b/internal/cdc/controller/controllerimpl/controller_impl.go new file mode 100644 index 0000000000..b6225c9f1f --- /dev/null +++ b/internal/cdc/controller/controllerimpl/controller_impl.go @@ -0,0 +1,83 @@ +// Licensed to the LF AI & Data foundation under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The 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 controllerimpl + +import ( + "context" + "sync" + "time" + + "go.uber.org/zap" + + "github.com/milvus-io/milvus/internal/cdc/resource" + "github.com/milvus-io/milvus/pkg/v2/log" +) + +const checkInterval = 10 * time.Second + +type controller struct { + ctx context.Context + wg sync.WaitGroup + stopOnce sync.Once + stopChan chan struct{} +} + +func NewController() *controller { + return &controller{ + ctx: context.Background(), + stopChan: make(chan struct{}), + } +} + +func (c *controller) Start() { + log.Ctx(c.ctx).Info("CDC controller started") + c.wg.Add(1) + go func() { + defer c.wg.Done() + timer := time.NewTicker(checkInterval) + defer timer.Stop() + for { + select { + case <-c.stopChan: + return + case <-timer.C: + c.run() + } + } + }() +} + +func (c *controller) Stop() { + c.stopOnce.Do(func() { + log.Ctx(c.ctx).Info("CDC controller stopping...") + // TODO: sheep, gracefully stop the replicators + close(c.stopChan) + c.wg.Wait() + log.Ctx(c.ctx).Info("CDC controller stopped") + }) +} + +func (c *controller) run() { + replicatePChannels, err := resource.Resource().ReplicationCatalog().ListReplicatePChannels(c.ctx) + if err != nil { + log.Ctx(c.ctx).Error("failed to get replicate pchannels", zap.Error(err)) + return + } + for _, replicatePChannel := range replicatePChannels { + resource.Resource().ReplicateManagerClient().CreateReplicator(replicatePChannel) + } +} diff --git a/internal/cdc/controller/controllerimpl/controller_impl_test.go b/internal/cdc/controller/controllerimpl/controller_impl_test.go new file mode 100644 index 0000000000..c60873dd7c --- /dev/null +++ b/internal/cdc/controller/controllerimpl/controller_impl_test.go @@ -0,0 +1,83 @@ +// Licensed to the LF AI & Data foundation under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The 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 controllerimpl + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + + "github.com/milvus-io/milvus/internal/cdc/replication" + "github.com/milvus-io/milvus/internal/cdc/resource" + "github.com/milvus-io/milvus/internal/mocks/mock_metastore" + "github.com/milvus-io/milvus/pkg/v2/proto/streamingpb" +) + +func TestController_StartAndStop(t *testing.T) { + mockReplicateManagerClient := replication.NewMockReplicateManagerClient(t) + resource.InitForTest(t, + resource.OptReplicateManagerClient(mockReplicateManagerClient), + ) + + ctrl := NewController() + assert.NotPanics(t, func() { + ctrl.Start() + }) + assert.NotPanics(t, func() { + ctrl.Stop() + }) +} + +func TestController_Run(t *testing.T) { + mockReplicateManagerClient := replication.NewMockReplicateManagerClient(t) + + replicatePChannels := []*streamingpb.ReplicatePChannelMeta{ + { + SourceChannelName: "test-source-channel-1", + TargetChannelName: "test-target-channel-1", + }, + } + mockReplicationCatalog := mock_metastore.NewMockReplicationCatalog(t) + mockReplicationCatalog.EXPECT().ListReplicatePChannels(mock.Anything).Return(replicatePChannels, nil) + mockReplicateManagerClient.EXPECT().CreateReplicator(replicatePChannels[0]).Return() + resource.InitForTest(t, + resource.OptReplicateManagerClient(mockReplicateManagerClient), + resource.OptReplicationCatalog(mockReplicationCatalog), + ) + + ctrl := NewController() + ctrl.Start() + defer ctrl.Stop() + ctrl.run() +} + +func TestController_RunError(t *testing.T) { + mockReplicateManagerClient := replication.NewMockReplicateManagerClient(t) + + mockReplicationCatalog := mock_metastore.NewMockReplicationCatalog(t) + mockReplicationCatalog.EXPECT().ListReplicatePChannels(mock.Anything).Return(nil, assert.AnError) + resource.InitForTest(t, + resource.OptReplicateManagerClient(mockReplicateManagerClient), + resource.OptReplicationCatalog(mockReplicationCatalog), + ) + + ctrl := NewController() + ctrl.Start() + defer ctrl.Stop() + ctrl.run() +} diff --git a/internal/cdc/controller/mock_controller.go b/internal/cdc/controller/mock_controller.go new file mode 100644 index 0000000000..d7f2ab4403 --- /dev/null +++ b/internal/cdc/controller/mock_controller.go @@ -0,0 +1,96 @@ +// Code generated by mockery v2.53.3. DO NOT EDIT. + +package controller + +import mock "github.com/stretchr/testify/mock" + +// MockController is an autogenerated mock type for the Controller type +type MockController struct { + mock.Mock +} + +type MockController_Expecter struct { + mock *mock.Mock +} + +func (_m *MockController) EXPECT() *MockController_Expecter { + return &MockController_Expecter{mock: &_m.Mock} +} + +// Start provides a mock function with no fields +func (_m *MockController) Start() { + _m.Called() +} + +// MockController_Start_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Start' +type MockController_Start_Call struct { + *mock.Call +} + +// Start is a helper method to define mock.On call +func (_e *MockController_Expecter) Start() *MockController_Start_Call { + return &MockController_Start_Call{Call: _e.mock.On("Start")} +} + +func (_c *MockController_Start_Call) Run(run func()) *MockController_Start_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockController_Start_Call) Return() *MockController_Start_Call { + _c.Call.Return() + return _c +} + +func (_c *MockController_Start_Call) RunAndReturn(run func()) *MockController_Start_Call { + _c.Run(run) + return _c +} + +// Stop provides a mock function with no fields +func (_m *MockController) Stop() { + _m.Called() +} + +// MockController_Stop_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Stop' +type MockController_Stop_Call struct { + *mock.Call +} + +// Stop is a helper method to define mock.On call +func (_e *MockController_Expecter) Stop() *MockController_Stop_Call { + return &MockController_Stop_Call{Call: _e.mock.On("Stop")} +} + +func (_c *MockController_Stop_Call) Run(run func()) *MockController_Stop_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockController_Stop_Call) Return() *MockController_Stop_Call { + _c.Call.Return() + return _c +} + +func (_c *MockController_Stop_Call) RunAndReturn(run func()) *MockController_Stop_Call { + _c.Run(run) + return _c +} + +// NewMockController creates a new instance of MockController. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockController(t interface { + mock.TestingT + Cleanup(func()) +}) *MockController { + mock := &MockController{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/internal/cdc/replication/mock_replicate_manager_client.go b/internal/cdc/replication/mock_replicate_manager_client.go new file mode 100644 index 0000000000..7943136ce7 --- /dev/null +++ b/internal/cdc/replication/mock_replicate_manager_client.go @@ -0,0 +1,68 @@ +// Code generated by mockery v2.53.3. DO NOT EDIT. + +package replication + +import ( + streamingpb "github.com/milvus-io/milvus/pkg/v2/proto/streamingpb" + mock "github.com/stretchr/testify/mock" +) + +// MockReplicateManagerClient is an autogenerated mock type for the ReplicateManagerClient type +type MockReplicateManagerClient struct { + mock.Mock +} + +type MockReplicateManagerClient_Expecter struct { + mock *mock.Mock +} + +func (_m *MockReplicateManagerClient) EXPECT() *MockReplicateManagerClient_Expecter { + return &MockReplicateManagerClient_Expecter{mock: &_m.Mock} +} + +// CreateReplicator provides a mock function with given fields: replicateInfo +func (_m *MockReplicateManagerClient) CreateReplicator(replicateInfo *streamingpb.ReplicatePChannelMeta) { + _m.Called(replicateInfo) +} + +// MockReplicateManagerClient_CreateReplicator_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateReplicator' +type MockReplicateManagerClient_CreateReplicator_Call struct { + *mock.Call +} + +// CreateReplicator is a helper method to define mock.On call +// - replicateInfo *streamingpb.ReplicatePChannelMeta +func (_e *MockReplicateManagerClient_Expecter) CreateReplicator(replicateInfo interface{}) *MockReplicateManagerClient_CreateReplicator_Call { + return &MockReplicateManagerClient_CreateReplicator_Call{Call: _e.mock.On("CreateReplicator", replicateInfo)} +} + +func (_c *MockReplicateManagerClient_CreateReplicator_Call) Run(run func(replicateInfo *streamingpb.ReplicatePChannelMeta)) *MockReplicateManagerClient_CreateReplicator_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*streamingpb.ReplicatePChannelMeta)) + }) + return _c +} + +func (_c *MockReplicateManagerClient_CreateReplicator_Call) Return() *MockReplicateManagerClient_CreateReplicator_Call { + _c.Call.Return() + return _c +} + +func (_c *MockReplicateManagerClient_CreateReplicator_Call) RunAndReturn(run func(*streamingpb.ReplicatePChannelMeta)) *MockReplicateManagerClient_CreateReplicator_Call { + _c.Run(run) + return _c +} + +// NewMockReplicateManagerClient creates a new instance of MockReplicateManagerClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockReplicateManagerClient(t interface { + mock.TestingT + Cleanup(func()) +}) *MockReplicateManagerClient { + mock := &MockReplicateManagerClient{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/internal/cdc/replication/replicate_manager_client.go b/internal/cdc/replication/replicate_manager_client.go new file mode 100644 index 0000000000..7b069abb6a --- /dev/null +++ b/internal/cdc/replication/replicate_manager_client.go @@ -0,0 +1,25 @@ +// Licensed to the LF AI & Data foundation under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The 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 replication + +import "github.com/milvus-io/milvus/pkg/v2/proto/streamingpb" + +// ReplicateManagerClient is the client that manages the replicate configuration. +type ReplicateManagerClient interface { + // CreateReplicator creates a new replicator for the replicate pchannel. + CreateReplicator(replicateInfo *streamingpb.ReplicatePChannelMeta) +} diff --git a/internal/cdc/replication/replicatemanager/channel_replicator.go b/internal/cdc/replication/replicatemanager/channel_replicator.go new file mode 100644 index 0000000000..ab59b1319d --- /dev/null +++ b/internal/cdc/replication/replicatemanager/channel_replicator.go @@ -0,0 +1,237 @@ +// Licensed to the LF AI & Data foundation under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The 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 replicatemanager + +import ( + "context" + "fmt" + "time" + + "go.uber.org/zap" + + "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" + "github.com/milvus-io/milvus/internal/cdc/replication/replicatestream" + "github.com/milvus-io/milvus/internal/cdc/resource" + "github.com/milvus-io/milvus/internal/distributed/streaming" + "github.com/milvus-io/milvus/pkg/v2/log" + "github.com/milvus-io/milvus/pkg/v2/proto/streamingpb" + "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" + "github.com/milvus-io/milvus/pkg/v2/streaming/util/message/adaptor" + "github.com/milvus-io/milvus/pkg/v2/streaming/util/options" + "github.com/milvus-io/milvus/pkg/v2/util/paramtable" + "github.com/milvus-io/milvus/pkg/v2/util/replicateutil" + "github.com/milvus-io/milvus/pkg/v2/util/typeutil" +) + +const scannerHandlerChanSize = 64 + +// Replicator is the client that replicates the message to the channel in the target cluster. +type Replicator interface { + // StartReplicate starts the replicate for the channel. + StartReplicate() + + // StopReplicate stops the replicate loop + // and wait for the loop to exit. + StopReplicate() + + // GetState returns the current state of the replicator. + GetState() typeutil.LifetimeState +} + +var _ Replicator = (*channelReplicator)(nil) + +// channelReplicator is the implementation of ChannelReplicator. +type channelReplicator struct { + replicateInfo *streamingpb.ReplicatePChannelMeta + createRscFunc replicatestream.CreateReplicateStreamClientFunc + + ctx context.Context + cancel context.CancelFunc + lifetime *typeutil.Lifetime +} + +// NewChannelReplicator creates a new ChannelReplicator. +func NewChannelReplicator(replicateMeta *streamingpb.ReplicatePChannelMeta) Replicator { + ctx, cancel := context.WithCancel(context.Background()) + createRscFunc := replicatestream.NewReplicateStreamClient + return &channelReplicator{ + replicateInfo: replicateMeta, + createRscFunc: createRscFunc, + ctx: ctx, + cancel: cancel, + lifetime: typeutil.NewLifetime(), + } +} + +func (r *channelReplicator) StartReplicate() { + logger := log.With( + zap.String("sourceChannel", r.replicateInfo.GetSourceChannelName()), + zap.String("targetChannel", r.replicateInfo.GetTargetChannelName()), + ) + if !r.lifetime.Add(typeutil.LifetimeStateWorking) { + logger.Warn("replicate channel already started") + return + } + logger.Info("start replicate channel") + go func() { + defer r.lifetime.Done() + for { + err := r.replicateLoop() + if err != nil { + logger.Warn("replicate channel failed", zap.Error(err)) + time.Sleep(10 * time.Second) + continue + } + break + } + logger.Info("stop replicate channel") + }() +} + +// replicateLoop starts the replicate loop. +func (r *channelReplicator) replicateLoop() error { + logger := log.With( + zap.String("sourceChannel", r.replicateInfo.GetSourceChannelName()), + zap.String("targetChannel", r.replicateInfo.GetTargetChannelName()), + ) + startFrom, err := r.getReplicateStartMessageID() + if err != nil { + return err + } + ch := make(adaptor.ChanMessageHandler, scannerHandlerChanSize) + var deliverPolicy options.DeliverPolicy + if startFrom == nil { + // No checkpoint found, seek from the earliest position + deliverPolicy = options.DeliverPolicyAll() + } else { + // Seek from the checkpoint + deliverPolicy = options.DeliverPolicyStartFrom(startFrom) + } + scanner := streaming.WAL().Read(r.ctx, streaming.ReadOption{ + PChannel: r.replicateInfo.GetSourceChannelName(), + DeliverPolicy: deliverPolicy, + DeliverFilters: []options.DeliverFilter{}, + MessageHandler: ch, + }) + defer scanner.Close() + + rsc := r.createRscFunc(r.ctx, r.replicateInfo) + defer rsc.Close() + + logger.Info("start replicate channel loop", zap.Any("startFrom", startFrom)) + + for { + select { + case <-r.ctx.Done(): + logger.Info("replicate channel stopped") + return nil + case msg := <-ch: + // TODO: Should be done at streamingnode. + if msg.MessageType().IsSelfControlled() { + logger.Debug("skip self-controlled message", log.FieldMessage(msg)) + continue + } + err := rsc.Replicate(msg) + if err != nil { + panic(fmt.Sprintf("replicate message failed due to unrecoverable error: %v", err)) + } + logger.Debug("replicate message success", log.FieldMessage(msg)) + if msg.MessageType() == message.MessageTypePutReplicateConfig { + roleChanged := r.handlePutReplicateConfigMessage(msg) + if roleChanged { + // Role changed, return and stop replicate. + return nil + } + } + } + } +} + +func (r *channelReplicator) getReplicateStartMessageID() (message.MessageID, error) { + logger := log.With( + zap.String("sourceChannel", r.replicateInfo.GetSourceChannelName()), + zap.String("targetChannel", r.replicateInfo.GetTargetChannelName()), + ) + + ctx, cancel := context.WithTimeout(r.ctx, 30*time.Second) + defer cancel() + milvusClient, err := resource.Resource().ClusterClient().CreateMilvusClient(ctx, r.replicateInfo.GetTargetCluster()) + if err != nil { + return nil, err + } + defer milvusClient.Close(ctx) + + sourceClusterID := paramtable.Get().CommonCfg.ClusterPrefix.GetValue() + replicateInfo, err := milvusClient.GetReplicateInfo(ctx, sourceClusterID) + if err != nil { + return nil, err + } + + var checkpoint *commonpb.ReplicateCheckpoint + for _, cp := range replicateInfo.GetCheckpoints() { + if cp.GetPchannel() == r.replicateInfo.GetSourceChannelName() { + checkpoint = cp + break + } + } + if checkpoint == nil || checkpoint.MessageId == nil { + logger.Info("channel not found in replicate info, will start from the beginning") + return nil, nil + } + + startFrom := message.MustUnmarshalMessageID(checkpoint.GetMessageId()) + logger.Info("replicate messages from position", + zap.Any("checkpoint", checkpoint), + zap.Any("startFromMessageID", startFrom), + ) + return startFrom, nil +} + +func (r *channelReplicator) handlePutReplicateConfigMessage(msg message.ImmutableMessage) (roleChanged bool) { + logger := log.With( + zap.String("sourceChannel", r.replicateInfo.GetSourceChannelName()), + zap.String("targetChannel", r.replicateInfo.GetTargetChannelName()), + ) + logger.Info("handle PutReplicateConfigMessage", log.FieldMessage(msg)) + prcMsg := message.MustAsImmutablePutReplicateConfigMessageV2(msg) + replicateConfig := prcMsg.Header().ReplicateConfiguration + currentClusterID := paramtable.Get().CommonCfg.ClusterPrefix.GetValue() + currentCluster := replicateutil.MustNewConfigHelper(currentClusterID, replicateConfig).GetCurrentCluster() + if currentCluster.Role() == replicateutil.RolePrimary { + logger.Info("primary cluster, skip handle PutReplicateConfigMessage") + return false + } + // Current cluster role changed, not primary cluster, + // we need to remove the replicate pchannel. + err := resource.Resource().ReplicationCatalog().RemoveReplicatePChannel(r.ctx, + r.replicateInfo.GetSourceChannelName(), r.replicateInfo.GetTargetChannelName()) + if err != nil { + panic(fmt.Sprintf("failed to remove replicate pchannel: %v", err)) + } + logger.Info("handle PutReplicateConfigMessage done, replicate pchannel removed") + return true +} + +func (r *channelReplicator) StopReplicate() { + r.lifetime.SetState(typeutil.LifetimeStateStopped) + r.cancel() + r.lifetime.Wait() +} + +func (r *channelReplicator) GetState() typeutil.LifetimeState { + return r.lifetime.GetState() +} diff --git a/internal/cdc/replication/replicatemanager/channel_replicator_test.go b/internal/cdc/replication/replicatemanager/channel_replicator_test.go new file mode 100644 index 0000000000..7055db9fa6 --- /dev/null +++ b/internal/cdc/replication/replicatemanager/channel_replicator_test.go @@ -0,0 +1,96 @@ +// Licensed to the LF AI & Data foundation under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The 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 replicatemanager + +import ( + "context" + "testing" + + "github.com/apache/pulsar-client-go/pulsar" + "github.com/stretchr/testify/assert" + mock "github.com/stretchr/testify/mock" + + "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" + "github.com/milvus-io/milvus-proto/go-api/v2/milvuspb" + "github.com/milvus-io/milvus/internal/cdc/cluster" + "github.com/milvus-io/milvus/internal/cdc/replication/replicatestream" + "github.com/milvus-io/milvus/internal/cdc/resource" + "github.com/milvus-io/milvus/internal/distributed/streaming" + "github.com/milvus-io/milvus/internal/mocks/distributed/mock_streaming" + "github.com/milvus-io/milvus/pkg/v2/proto/streamingpb" + pulsar2 "github.com/milvus-io/milvus/pkg/v2/streaming/walimpls/impls/pulsar" + "github.com/milvus-io/milvus/pkg/v2/util/typeutil" +) + +func newMockPulsarMessageID() *commonpb.MessageID { + pulsarID := pulsar.EarliestMessageID() + msgID := pulsar2.NewPulsarID(pulsarID).Marshal() + return &commonpb.MessageID{ + Id: msgID, + WALName: commonpb.WALName_Pulsar, + } +} + +func TestChannelReplicator_StartReplicateChannel(t *testing.T) { + mockMilvusClient := cluster.NewMockMilvusClient(t) + mockMilvusClient.EXPECT().GetReplicateInfo(mock.Anything, mock.Anything). + Return(&milvuspb.GetReplicateInfoResponse{ + Checkpoints: []*commonpb.ReplicateCheckpoint{ + { + Pchannel: "test-source-channel", + MessageId: newMockPulsarMessageID(), + }, + }, + }, nil) + mockMilvusClient.EXPECT().Close(mock.Anything).Return(nil) + + mockClusterClient := cluster.NewMockClusterClient(t) + mockClusterClient.EXPECT().CreateMilvusClient(mock.Anything, mock.Anything). + Return(mockMilvusClient, nil) + resource.InitForTest(t, + resource.OptClusterClient(mockClusterClient), + ) + + scanner := mock_streaming.NewMockScanner(t) + scanner.EXPECT().Close().Return() + wal := mock_streaming.NewMockWALAccesser(t) + wal.EXPECT().Read(mock.Anything, mock.Anything).Return(scanner) + streaming.SetWALForTest(wal) + + rs := replicatestream.NewMockReplicateStreamClient(t) + rs.EXPECT().Close().Return() + + cluster := &commonpb.MilvusCluster{ClusterId: "test-cluster"} + replicateInfo := &streamingpb.ReplicatePChannelMeta{ + SourceChannelName: "test-source-channel", + TargetChannelName: "test-target-channel", + TargetCluster: cluster, + } + replicator := NewChannelReplicator(replicateInfo) + replicator.(*channelReplicator).createRscFunc = func(ctx context.Context, + replicateInfo *streamingpb.ReplicatePChannelMeta, + ) replicatestream.ReplicateStreamClient { + return rs + } + assert.NotNil(t, replicator) + + replicator.StartReplicate() + replicator.StopReplicate() + + state := replicator.GetState() + assert.Equal(t, typeutil.LifetimeStateStopped, state) +} diff --git a/internal/cdc/replication/replicatemanager/mock_channel_replicator.go b/internal/cdc/replication/replicatemanager/mock_channel_replicator.go new file mode 100644 index 0000000000..d464804773 --- /dev/null +++ b/internal/cdc/replication/replicatemanager/mock_channel_replicator.go @@ -0,0 +1,144 @@ +// Code generated by mockery v2.53.3. DO NOT EDIT. + +package replicatemanager + +import ( + typeutil "github.com/milvus-io/milvus/pkg/v2/util/typeutil" + mock "github.com/stretchr/testify/mock" +) + +// MockChannelReplicator is an autogenerated mock type for the ChannelReplicator type +type MockChannelReplicator struct { + mock.Mock +} + +type MockChannelReplicator_Expecter struct { + mock *mock.Mock +} + +func (_m *MockChannelReplicator) EXPECT() *MockChannelReplicator_Expecter { + return &MockChannelReplicator_Expecter{mock: &_m.Mock} +} + +// GetState provides a mock function with no fields +func (_m *MockChannelReplicator) GetState() typeutil.LifetimeState { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for GetState") + } + + var r0 typeutil.LifetimeState + if rf, ok := ret.Get(0).(func() typeutil.LifetimeState); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(typeutil.LifetimeState) + } + + return r0 +} + +// MockChannelReplicator_GetState_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetState' +type MockChannelReplicator_GetState_Call struct { + *mock.Call +} + +// GetState is a helper method to define mock.On call +func (_e *MockChannelReplicator_Expecter) GetState() *MockChannelReplicator_GetState_Call { + return &MockChannelReplicator_GetState_Call{Call: _e.mock.On("GetState")} +} + +func (_c *MockChannelReplicator_GetState_Call) Run(run func()) *MockChannelReplicator_GetState_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockChannelReplicator_GetState_Call) Return(_a0 typeutil.LifetimeState) *MockChannelReplicator_GetState_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockChannelReplicator_GetState_Call) RunAndReturn(run func() typeutil.LifetimeState) *MockChannelReplicator_GetState_Call { + _c.Call.Return(run) + return _c +} + +// StartReplicateChannel provides a mock function with no fields +func (_m *MockChannelReplicator) StartReplicateChannel() { + _m.Called() +} + +// MockChannelReplicator_StartReplicateChannel_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'StartReplicateChannel' +type MockChannelReplicator_StartReplicateChannel_Call struct { + *mock.Call +} + +// StartReplicateChannel is a helper method to define mock.On call +func (_e *MockChannelReplicator_Expecter) StartReplicateChannel() *MockChannelReplicator_StartReplicateChannel_Call { + return &MockChannelReplicator_StartReplicateChannel_Call{Call: _e.mock.On("StartReplicateChannel")} +} + +func (_c *MockChannelReplicator_StartReplicateChannel_Call) Run(run func()) *MockChannelReplicator_StartReplicateChannel_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockChannelReplicator_StartReplicateChannel_Call) Return() *MockChannelReplicator_StartReplicateChannel_Call { + _c.Call.Return() + return _c +} + +func (_c *MockChannelReplicator_StartReplicateChannel_Call) RunAndReturn(run func()) *MockChannelReplicator_StartReplicateChannel_Call { + _c.Run(run) + return _c +} + +// StopReplicateChannel provides a mock function with no fields +func (_m *MockChannelReplicator) StopReplicateChannel() { + _m.Called() +} + +// MockChannelReplicator_StopReplicateChannel_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'StopReplicateChannel' +type MockChannelReplicator_StopReplicateChannel_Call struct { + *mock.Call +} + +// StopReplicateChannel is a helper method to define mock.On call +func (_e *MockChannelReplicator_Expecter) StopReplicateChannel() *MockChannelReplicator_StopReplicateChannel_Call { + return &MockChannelReplicator_StopReplicateChannel_Call{Call: _e.mock.On("StopReplicateChannel")} +} + +func (_c *MockChannelReplicator_StopReplicateChannel_Call) Run(run func()) *MockChannelReplicator_StopReplicateChannel_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockChannelReplicator_StopReplicateChannel_Call) Return() *MockChannelReplicator_StopReplicateChannel_Call { + _c.Call.Return() + return _c +} + +func (_c *MockChannelReplicator_StopReplicateChannel_Call) RunAndReturn(run func()) *MockChannelReplicator_StopReplicateChannel_Call { + _c.Run(run) + return _c +} + +// NewMockChannelReplicator creates a new instance of MockChannelReplicator. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockChannelReplicator(t interface { + mock.TestingT + Cleanup(func()) +}) *MockChannelReplicator { + mock := &MockChannelReplicator{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/internal/cdc/replication/replicatemanager/replicate_manager.go b/internal/cdc/replication/replicatemanager/replicate_manager.go new file mode 100644 index 0000000000..69da7d8d3e --- /dev/null +++ b/internal/cdc/replication/replicatemanager/replicate_manager.go @@ -0,0 +1,64 @@ +// Licensed to the LF AI & Data foundation under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The 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 replicatemanager + +import ( + "context" + "strings" + + "go.uber.org/zap" + + "github.com/milvus-io/milvus/pkg/v2/log" + "github.com/milvus-io/milvus/pkg/v2/proto/streamingpb" + "github.com/milvus-io/milvus/pkg/v2/util/paramtable" +) + +// replicateManager is the implementation of ReplicateManagerClient. +type replicateManager struct { + ctx context.Context + + // replicators is a map of replicate pchannel name to ChannelReplicator. + replicators map[string]Replicator +} + +func NewReplicateManager() *replicateManager { + return &replicateManager{ + ctx: context.Background(), + replicators: make(map[string]Replicator), + } +} + +func (r *replicateManager) CreateReplicator(replicateInfo *streamingpb.ReplicatePChannelMeta) { + logger := log.With( + zap.String("sourceChannel", replicateInfo.GetSourceChannelName()), + zap.String("targetChannel", replicateInfo.GetTargetChannelName()), + ) + currentClusterID := paramtable.Get().CommonCfg.ClusterPrefix.GetValue() + if !strings.Contains(replicateInfo.GetSourceChannelName(), currentClusterID) { + // current cluster is not source cluster, skip create replicator + return + } + _, ok := r.replicators[replicateInfo.GetSourceChannelName()] + if ok { + logger.Debug("replicator already exists, skip create replicator") + return + } + replicator := NewChannelReplicator(replicateInfo) + replicator.StartReplicate() + r.replicators[replicateInfo.GetSourceChannelName()] = replicator + logger.Info("created replicator for replicate pchannel") +} diff --git a/internal/cdc/replication/replicatemanager/replicate_manager_test.go b/internal/cdc/replication/replicatemanager/replicate_manager_test.go new file mode 100644 index 0000000000..21ceffe231 --- /dev/null +++ b/internal/cdc/replication/replicatemanager/replicate_manager_test.go @@ -0,0 +1,88 @@ +// Licensed to the LF AI & Data foundation under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The 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 replicatemanager + +import ( + "testing" + + "github.com/stretchr/testify/assert" + mock "github.com/stretchr/testify/mock" + + "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" + "github.com/milvus-io/milvus/internal/cdc/cluster" + "github.com/milvus-io/milvus/internal/cdc/resource" + "github.com/milvus-io/milvus/pkg/v2/proto/streamingpb" + "github.com/milvus-io/milvus/pkg/v2/util/paramtable" +) + +func TestReplicateManager_CreateReplicator(t *testing.T) { + paramtable.Get().Save(paramtable.Get().CommonCfg.ClusterPrefix.Key, "test-source") + defer paramtable.Get().Reset(paramtable.Get().CommonCfg.ClusterPrefix.Key) + + mockMilvusClient := cluster.NewMockMilvusClient(t) + mockMilvusClient.EXPECT().GetReplicateInfo(mock.Anything, mock.Anything). + Return(nil, assert.AnError).Maybe() + mockMilvusClient.EXPECT().Close(mock.Anything).Return(nil).Maybe() + + mockClusterClient := cluster.NewMockClusterClient(t) + mockClusterClient.EXPECT().CreateMilvusClient(mock.Anything, mock.Anything). + Return(mockMilvusClient, nil).Maybe() + resource.InitForTest(t, + resource.OptClusterClient(mockClusterClient), + ) + + manager := NewReplicateManager() + + // Test creating first replicator + replicateInfo := &streamingpb.ReplicatePChannelMeta{ + SourceChannelName: "test-source-channel-1", + TargetChannelName: "test-target-channel-1", + TargetCluster: &commonpb.MilvusCluster{ + ClusterId: "test-cluster-1", + }, + } + + manager.CreateReplicator(replicateInfo) + + // Verify replicator was created + assert.Equal(t, 1, len(manager.replicators)) + replicator, exists := manager.replicators["test-source-channel-1"] + assert.True(t, exists) + assert.NotNil(t, replicator) + + // Test creating second replicator + replicateInfo2 := &streamingpb.ReplicatePChannelMeta{ + SourceChannelName: "test-source-channel-2", + TargetChannelName: "test-target-channel-2", + TargetCluster: &commonpb.MilvusCluster{ + ClusterId: "test-cluster-2", + }, + } + + manager.CreateReplicator(replicateInfo2) + + // Verify second replicator was created + assert.Equal(t, 2, len(manager.replicators)) + replicator2, exists := manager.replicators["test-source-channel-2"] + assert.True(t, exists) + assert.NotNil(t, replicator2) + + // Verify first replicator still exists + replicator1, exists := manager.replicators["test-source-channel-1"] + assert.True(t, exists) + assert.NotNil(t, replicator1) +} diff --git a/internal/cdc/replication/replicatestream/metrics.go b/internal/cdc/replication/replicatestream/metrics.go new file mode 100644 index 0000000000..7f3946a189 --- /dev/null +++ b/internal/cdc/replication/replicatestream/metrics.go @@ -0,0 +1,121 @@ +// Licensed to the LF AI & Data foundation under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The 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 replicatestream + +import ( + "github.com/milvus-io/milvus/pkg/v2/metrics" + streamingpb "github.com/milvus-io/milvus/pkg/v2/proto/streamingpb" + message "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" + "github.com/milvus-io/milvus/pkg/v2/util/timerecord" + "github.com/milvus-io/milvus/pkg/v2/util/typeutil" +) + +type ReplicateMetrics interface { + StartReplicate(msg message.ImmutableMessage) + OnSent(msg message.ImmutableMessage) + OnConfirmed(msg message.ImmutableMessage) + OnConnect() + OnDisconnect() + OnReconnect() +} + +type msgMetrics struct { + tr *timerecord.TimeRecorder +} + +type replicateMetrics struct { + replicateInfo *streamingpb.ReplicatePChannelMeta + msgsMetrics *typeutil.ConcurrentMap[string, msgMetrics] // message id -> msgMetrics +} + +func NewReplicateMetrics(replicateInfo *streamingpb.ReplicatePChannelMeta) ReplicateMetrics { + return &replicateMetrics{ + replicateInfo: replicateInfo, + msgsMetrics: typeutil.NewConcurrentMap[string, msgMetrics](), + } +} + +func (m *replicateMetrics) StartReplicate(msg message.ImmutableMessage) { + msgID := msg.MessageID().String() + m.msgsMetrics.Insert(msgID, msgMetrics{ + tr: timerecord.NewTimeRecorder("replicate_msg"), + }) +} + +func (m *replicateMetrics) OnSent(msg message.ImmutableMessage) { + sourceChannel := m.replicateInfo.GetSourceChannelName() + targetChannel := m.replicateInfo.GetTargetChannelName() + msgType := msg.MessageType().String() + metrics.CDCReplicatedMessagesTotal.WithLabelValues( + sourceChannel, + targetChannel, + msgType, + ).Inc() + metrics.CDCReplicatedBytesTotal.WithLabelValues( + sourceChannel, + targetChannel, + msgType, + ).Add(float64(msg.EstimateSize())) +} + +func (m *replicateMetrics) OnConfirmed(msg message.ImmutableMessage) { + msgMetrics, ok := m.msgsMetrics.GetAndRemove(msg.MessageID().String()) + if !ok { + return + } + + replicateDuration := msgMetrics.tr.RecordSpan() + metrics.CDCReplicateEndToEndLatency.WithLabelValues( + m.replicateInfo.GetSourceChannelName(), + m.replicateInfo.GetTargetChannelName(), + ).Observe(float64(replicateDuration.Milliseconds())) +} + +func (m *replicateMetrics) OnConnect() { + metrics.CDCStreamRPCConnections.WithLabelValues( + m.replicateInfo.GetTargetCluster().GetClusterId(), + metrics.CDCStatusConnected, + ).Inc() +} + +func (m *replicateMetrics) OnDisconnect() { + clusterID := m.replicateInfo.GetTargetCluster().GetClusterId() + metrics.CDCStreamRPCConnections.WithLabelValues( + clusterID, + metrics.CDCStatusConnected, + ).Dec() + metrics.CDCStreamRPCConnections.WithLabelValues( + clusterID, + metrics.CDCStatusDisconnected, + ).Inc() +} + +func (m *replicateMetrics) OnReconnect() { + clusterID := m.replicateInfo.GetTargetCluster().GetClusterId() + metrics.CDCStreamRPCConnections.WithLabelValues( + clusterID, + metrics.CDCStatusDisconnected, + ).Dec() + metrics.CDCStreamRPCConnections.WithLabelValues( + clusterID, + metrics.CDCStatusConnected, + ).Inc() + + metrics.CDCStreamRPCReconnectTimes.WithLabelValues( + clusterID, + ).Inc() +} diff --git a/internal/cdc/replication/replicatestream/mock_replicate_stream_client.go b/internal/cdc/replication/replicatestream/mock_replicate_stream_client.go new file mode 100644 index 0000000000..16743e8b11 --- /dev/null +++ b/internal/cdc/replication/replicatestream/mock_replicate_stream_client.go @@ -0,0 +1,113 @@ +// Code generated by mockery v2.53.3. DO NOT EDIT. + +package replicatestream + +import ( + message "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" + mock "github.com/stretchr/testify/mock" +) + +// MockReplicateStreamClient is an autogenerated mock type for the ReplicateStreamClient type +type MockReplicateStreamClient struct { + mock.Mock +} + +type MockReplicateStreamClient_Expecter struct { + mock *mock.Mock +} + +func (_m *MockReplicateStreamClient) EXPECT() *MockReplicateStreamClient_Expecter { + return &MockReplicateStreamClient_Expecter{mock: &_m.Mock} +} + +// Close provides a mock function with no fields +func (_m *MockReplicateStreamClient) Close() { + _m.Called() +} + +// MockReplicateStreamClient_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close' +type MockReplicateStreamClient_Close_Call struct { + *mock.Call +} + +// Close is a helper method to define mock.On call +func (_e *MockReplicateStreamClient_Expecter) Close() *MockReplicateStreamClient_Close_Call { + return &MockReplicateStreamClient_Close_Call{Call: _e.mock.On("Close")} +} + +func (_c *MockReplicateStreamClient_Close_Call) Run(run func()) *MockReplicateStreamClient_Close_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockReplicateStreamClient_Close_Call) Return() *MockReplicateStreamClient_Close_Call { + _c.Call.Return() + return _c +} + +func (_c *MockReplicateStreamClient_Close_Call) RunAndReturn(run func()) *MockReplicateStreamClient_Close_Call { + _c.Run(run) + return _c +} + +// Replicate provides a mock function with given fields: msg +func (_m *MockReplicateStreamClient) Replicate(msg message.ImmutableMessage) error { + ret := _m.Called(msg) + + if len(ret) == 0 { + panic("no return value specified for Replicate") + } + + var r0 error + if rf, ok := ret.Get(0).(func(message.ImmutableMessage) error); ok { + r0 = rf(msg) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockReplicateStreamClient_Replicate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Replicate' +type MockReplicateStreamClient_Replicate_Call struct { + *mock.Call +} + +// Replicate is a helper method to define mock.On call +// - msg message.ImmutableMessage +func (_e *MockReplicateStreamClient_Expecter) Replicate(msg interface{}) *MockReplicateStreamClient_Replicate_Call { + return &MockReplicateStreamClient_Replicate_Call{Call: _e.mock.On("Replicate", msg)} +} + +func (_c *MockReplicateStreamClient_Replicate_Call) Run(run func(msg message.ImmutableMessage)) *MockReplicateStreamClient_Replicate_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(message.ImmutableMessage)) + }) + return _c +} + +func (_c *MockReplicateStreamClient_Replicate_Call) Return(_a0 error) *MockReplicateStreamClient_Replicate_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockReplicateStreamClient_Replicate_Call) RunAndReturn(run func(message.ImmutableMessage) error) *MockReplicateStreamClient_Replicate_Call { + _c.Call.Return(run) + return _c +} + +// NewMockReplicateStreamClient creates a new instance of MockReplicateStreamClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockReplicateStreamClient(t interface { + mock.TestingT + Cleanup(func()) +}) *MockReplicateStreamClient { + mock := &MockReplicateStreamClient{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/internal/cdc/replication/replicatestream/msg_queue.go b/internal/cdc/replication/replicatestream/msg_queue.go new file mode 100644 index 0000000000..cecdd03985 --- /dev/null +++ b/internal/cdc/replication/replicatestream/msg_queue.go @@ -0,0 +1,211 @@ +// Licensed to the LF AI & Data foundation under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The 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 replicatestream + +import ( + "context" + "sync" + + message "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" +) + +// MsgQueue exposes the required operations. We include context support to meet the +// blocking + cancel requirements. +// The names mirror the user's suggestion with small adjustments for clarity. +type MsgQueue interface { + // Enqueue appends a message. Blocks if capacity is full until space appears + // (via CleanupConfirmedMessages) or ctx is canceled. + Enqueue(ctx context.Context, msg message.ImmutableMessage) error + + // Dequeue returns the next message from the current read cursor and advances + // the cursor by one. It does NOT delete the message from the queue storage. + // Blocks when there are no readable messages (i.e., cursor is at tail) until + // a new message is Enqueued or ctx is canceled. + Dequeue(ctx context.Context) (message.ImmutableMessage, error) + + // SeekToHead moves the read cursor to the first not-yet-deleted message. + SeekToHead() + + // CleanupConfirmedMessages permanently removes all messages whose Timetick() + // <= lastConfirmedTimeTick. This may free capacity and wake Enqueue waiters. + // Returns the messages that were cleaned up. + CleanupConfirmedMessages(lastConfirmedTimeTick uint64) []message.ImmutableMessage + + // Len returns the number of stored (not yet deleted) messages. + Len() int + + // Cap returns the maximum capacity of the queue. + Cap() int +} + +var _ MsgQueue = (*msgQueue)(nil) + +// msgQueue is a bounded, in-memory implementation of MsgQueue. +// It uses a simple slice for storage and an integer read cursor that is always +// within [0, len(buf)]. +type msgQueue struct { + mu sync.Mutex + notEmpty *sync.Cond + notFull *sync.Cond + + buf []message.ImmutableMessage + readIdx int + cap int + closed bool +} + +// NewMsgQueue creates a queue with a fixed capacity (>0). +func NewMsgQueue(capacity int) *msgQueue { + if capacity <= 0 { + panic("capacity must be > 0") + } + q := &msgQueue{cap: capacity} + q.notEmpty = sync.NewCond(&q.mu) + q.notFull = sync.NewCond(&q.mu) + return q +} + +func (q *msgQueue) Len() int { + q.mu.Lock() + defer q.mu.Unlock() + return len(q.buf) +} + +func (q *msgQueue) Cap() int { return q.cap } + +// Enqueue implements a blocking producer. It respects ctx cancellation. +func (q *msgQueue) Enqueue(ctx context.Context, msg message.ImmutableMessage) error { + q.mu.Lock() + defer q.mu.Unlock() + + for len(q.buf) >= q.cap { + if ctx.Err() != nil { + return context.Canceled + } + q.waitWithContext(ctx, q.notFull) + if ctx.Err() != nil { + return context.Canceled + } + } + + // Optional runtime check: enforce non-decreasing timetick + // if n := len(q.buf); n > 0 { + // if q.buf[n-1].Timetick() > msg.Timetick() { + // return fmt.Errorf("enqueue timetick order violation: last=%d new=%d", q.buf[n-1].Timetick(), msg.Timetick()) + // } + // } + + q.buf = append(q.buf, msg) + + // New data is available for readers. + q.notEmpty.Signal() + return nil +} + +// Dequeue returns the next message at the read cursor. Does not delete it. +func (q *msgQueue) Dequeue(ctx context.Context) (message.ImmutableMessage, error) { + q.mu.Lock() + defer q.mu.Unlock() + + for q.readIdx >= len(q.buf) { // no readable messages + if ctx.Err() != nil { + return nil, context.Canceled + } + q.waitWithContext(ctx, q.notEmpty) + if ctx.Err() != nil { + return nil, context.Canceled + } + } + + m := q.buf[q.readIdx] + q.readIdx++ // advance read cursor only; storage remains intact + + // Readers advancing may not directly free capacity, but producers may still + // be waiting due to full buffer; signal in case cleanup made space earlier. + q.notFull.Signal() + return m, nil +} + +// SeekToHead resets the read cursor to the first existing element. +func (q *msgQueue) SeekToHead() { + q.mu.Lock() + q.readIdx = 0 + // Let potential consumers know there's readable data (if any exists). + if len(q.buf) > 0 { + q.notEmpty.Broadcast() + } + q.mu.Unlock() +} + +// CleanupConfirmedMessages permanently drops messages with Timetick <= watermark. +// This frees capacity and may move the read cursor backward proportionally to the +// number of deleted messages (but clamped at 0). +// Returns the messages that were cleaned up. +func (q *msgQueue) CleanupConfirmedMessages(lastConfirmedTimeTick uint64) []message.ImmutableMessage { + q.mu.Lock() + defer q.mu.Unlock() + + if len(q.buf) == 0 { + return nil + } + + // Find first index whose Timetick() > lastConfirmedTimeTick + cut := 0 + for cut < len(q.buf) && q.buf[cut].TimeTick() <= lastConfirmedTimeTick { + cut++ + } + + var cleanedMessages []message.ImmutableMessage + if cut > 0 { + // Collect the messages that will be cleaned up + cleanedMessages = make([]message.ImmutableMessage, cut) + copy(cleanedMessages, q.buf[:cut]) + + // Drop the prefix [0:cut) + q.buf = q.buf[cut:] + // Adjust read cursor relative to the new slice + q.readIdx -= cut + if q.readIdx < 0 { + q.readIdx = 0 + } + // Free space became available; wake blocked producers. + q.notFull.Broadcast() + } + + return cleanedMessages +} + +// waitWithContext waits on cond while allowing ctx cancellation to wake it up. +// Implementation detail: +// - cond.Wait() requires holding q.mu; Wait atomically unlocks and re-locks. +// - We spawn a short-lived goroutine that Broadcasts on ctx.Done(). This is +// safe and bounded: after Wait returns, we close a local channel to let the +// goroutine exit immediately (even if ctx wasn't canceled). +func (q *msgQueue) waitWithContext(ctx context.Context, cond *sync.Cond) { + done := make(chan struct{}) + go func() { + select { + case <-ctx.Done(): + q.mu.Lock() + cond.Broadcast() + q.mu.Unlock() + case <-done: + } + }() + cond.Wait() // releases q.mu while waiting; re-locks before returning + close(done) +} diff --git a/internal/cdc/replication/replicatestream/msg_queue_test.go b/internal/cdc/replication/replicatestream/msg_queue_test.go new file mode 100644 index 0000000000..f08a1a3f91 --- /dev/null +++ b/internal/cdc/replication/replicatestream/msg_queue_test.go @@ -0,0 +1,287 @@ +// Licensed to the LF AI & Data foundation under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The 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 replicatestream + +import ( + "context" + "sync" + "testing" + "time" + + "github.com/stretchr/testify/assert" + + "github.com/milvus-io/milvus/pkg/v2/mocks/streaming/util/mock_message" +) + +func TestMsgQueue_BasicOperations(t *testing.T) { + // Test basic queue operations + queue := NewMsgQueue(3) + assert.Equal(t, 3, queue.Cap()) + assert.Equal(t, 0, queue.Len()) + + // Test enqueue and dequeue + ctx := context.Background() + msg1 := mock_message.NewMockImmutableMessage(t) + msg1.EXPECT().TimeTick().Return(uint64(100)).Maybe() + + err := queue.Enqueue(ctx, msg1) + assert.NoError(t, err) + assert.Equal(t, 1, queue.Len()) + + // Test dequeue + dequeuedMsg, err := queue.Dequeue(ctx) + assert.NoError(t, err) + assert.Equal(t, msg1, dequeuedMsg) + assert.Equal(t, 1, queue.Len()) // Length doesn't change after dequeue +} + +func TestMsgQueue_EnqueueBlocking(t *testing.T) { + // Test enqueue blocking when queue is full + queue := NewMsgQueue(2) + ctx := context.Background() + + // Fill the queue + msg1 := mock_message.NewMockImmutableMessage(t) + msg1.EXPECT().TimeTick().Return(uint64(100)).Maybe() + msg2 := mock_message.NewMockImmutableMessage(t) + msg2.EXPECT().TimeTick().Return(uint64(200)).Maybe() + + err := queue.Enqueue(ctx, msg1) + assert.NoError(t, err) + err = queue.Enqueue(ctx, msg2) + assert.NoError(t, err) + assert.Equal(t, 2, queue.Len()) + + // Try to enqueue when full - should block + msg3 := mock_message.NewMockImmutableMessage(t) + msg3.EXPECT().TimeTick().Return(uint64(300)).Maybe() + + // Use a context with timeout to test blocking + ctxWithTimeout, cancel := context.WithTimeout(ctx, 100*time.Millisecond) + defer cancel() + + err = queue.Enqueue(ctxWithTimeout, msg3) + assert.Error(t, err) + // Context timeout will cause context.Canceled error, not DeadlineExceeded + assert.Equal(t, context.Canceled, err) +} + +func TestMsgQueue_DequeueBlocking(t *testing.T) { + // Test dequeue blocking when queue is empty + queue := NewMsgQueue(2) + ctx := context.Background() + + // Try to dequeue from empty queue - should block + ctxWithTimeout, cancel := context.WithTimeout(ctx, 100*time.Millisecond) + defer cancel() + + _, err := queue.Dequeue(ctxWithTimeout) + assert.Error(t, err) + // Context timeout will cause context.Canceled error, not DeadlineExceeded + assert.Equal(t, context.Canceled, err) +} + +func TestMsgQueue_SeekToHead(t *testing.T) { + // Test seek to head functionality + queue := NewMsgQueue(3) + ctx := context.Background() + + // Add messages + msg1 := mock_message.NewMockImmutableMessage(t) + msg1.EXPECT().TimeTick().Return(uint64(100)).Maybe() + msg2 := mock_message.NewMockImmutableMessage(t) + msg2.EXPECT().TimeTick().Return(uint64(200)).Maybe() + + err := queue.Enqueue(ctx, msg1) + assert.NoError(t, err) + err = queue.Enqueue(ctx, msg2) + assert.NoError(t, err) + + // Dequeue first message + dequeuedMsg, err := queue.Dequeue(ctx) + assert.NoError(t, err) + assert.Equal(t, msg1, dequeuedMsg) + + // Seek to head + queue.SeekToHead() + + // Should be able to dequeue first message again + dequeuedMsg, err = queue.Dequeue(ctx) + assert.NoError(t, err) + assert.Equal(t, msg1, dequeuedMsg) +} + +func TestMsgQueue_CleanupConfirmedMessages(t *testing.T) { + // Test cleanup functionality + queue := NewMsgQueue(5) + ctx := context.Background() + + // Add messages with different timeticks + msg1 := mock_message.NewMockImmutableMessage(t) + msg1.EXPECT().TimeTick().Return(uint64(100)).Maybe() + msg2 := mock_message.NewMockImmutableMessage(t) + msg2.EXPECT().TimeTick().Return(uint64(200)).Maybe() + msg3 := mock_message.NewMockImmutableMessage(t) + msg3.EXPECT().TimeTick().Return(uint64(300)).Maybe() + + err := queue.Enqueue(ctx, msg1) + assert.NoError(t, err) + err = queue.Enqueue(ctx, msg2) + assert.NoError(t, err) + err = queue.Enqueue(ctx, msg3) + assert.NoError(t, err) + + assert.Equal(t, 3, queue.Len()) + + // Cleanup messages with timetick <= 200 + cleanedMessages := queue.CleanupConfirmedMessages(200) + assert.Equal(t, 1, queue.Len()) + assert.Equal(t, 2, len(cleanedMessages)) + assert.Equal(t, msg1, cleanedMessages[0]) + assert.Equal(t, msg2, cleanedMessages[1]) + + // First two messages should be removed + dequeuedMsg, err := queue.Dequeue(ctx) + assert.NoError(t, err) + assert.Equal(t, msg3, dequeuedMsg) // Only msg3 remains +} + +func TestMsgQueue_CleanupWithReadCursor(t *testing.T) { + // Test cleanup when read cursor is advanced + queue := NewMsgQueue(5) + ctx := context.Background() + + // Add messages + msg1 := mock_message.NewMockImmutableMessage(t) + msg1.EXPECT().TimeTick().Return(uint64(100)).Maybe() + msg2 := mock_message.NewMockImmutableMessage(t) + msg2.EXPECT().TimeTick().Return(uint64(200)).Maybe() + msg3 := mock_message.NewMockImmutableMessage(t) + msg3.EXPECT().TimeTick().Return(uint64(300)).Maybe() + + err := queue.Enqueue(ctx, msg1) + assert.NoError(t, err) + err = queue.Enqueue(ctx, msg2) + assert.NoError(t, err) + err = queue.Enqueue(ctx, msg3) + assert.NoError(t, err) + + // Dequeue first message (advance read cursor) + dequeuedMsg, err := queue.Dequeue(ctx) + assert.NoError(t, err) + assert.Equal(t, msg1, dequeuedMsg) + assert.Equal(t, 1, queue.readIdx) + + // Cleanup messages with timetick <= 150 + cleanedMessages := queue.CleanupConfirmedMessages(150) + assert.Equal(t, 2, queue.Len()) // msg1 removed, msg2 and msg3 remain + assert.Equal(t, 0, queue.readIdx) // read cursor adjusted + assert.Equal(t, 1, len(cleanedMessages)) + assert.Equal(t, msg1, cleanedMessages[0]) +} + +func TestMsgQueue_ContextCancellation(t *testing.T) { + // Test context cancellation + queue := NewMsgQueue(1) + ctx, cancel := context.WithCancel(context.Background()) + + // Fill the queue + msg1 := mock_message.NewMockImmutableMessage(t) + msg1.EXPECT().TimeTick().Return(uint64(100)).Maybe() + err := queue.Enqueue(ctx, msg1) + assert.NoError(t, err) + + // Try to enqueue when full + msg2 := mock_message.NewMockImmutableMessage(t) + msg2.EXPECT().TimeTick().Return(uint64(200)).Maybe() + + // Cancel context before enqueue + cancel() + err = queue.Enqueue(ctx, msg2) + assert.Error(t, err) + assert.Equal(t, context.Canceled, err) +} + +func TestMsgQueue_NewMsgQueueValidation(t *testing.T) { + // Test constructor validation + assert.Panics(t, func() { + NewMsgQueue(0) + }) + + assert.Panics(t, func() { + NewMsgQueue(-1) + }) + + // Valid capacity + queue := NewMsgQueue(1) + assert.NotNil(t, queue) + assert.Equal(t, 1, queue.Cap()) +} + +func TestMsgQueue_ConcurrentOperations(t *testing.T) { + // Test concurrent enqueue and dequeue operations + queue := NewMsgQueue(10) + ctx := context.Background() + numMessages := 100 + + wg := sync.WaitGroup{} + // Start producer goroutine + wg.Add(1) + go func() { + defer wg.Done() + for i := 0; i < numMessages; i++ { + msg := mock_message.NewMockImmutableMessage(t) + msg.EXPECT().TimeTick().Return(uint64(i)).Maybe() + err := queue.Enqueue(ctx, msg) + assert.NoError(t, err) + } + }() + + // Start consumer goroutine + wg.Add(1) + go func() { + defer wg.Done() + for i := 0; i < numMessages; i++ { + dequeuedMsg, err := queue.Dequeue(ctx) + assert.NoError(t, err) + cleanedMessages := queue.CleanupConfirmedMessages(dequeuedMsg.TimeTick()) + assert.Equal(t, 1, len(cleanedMessages)) + assert.Equal(t, dequeuedMsg, cleanedMessages[0]) + } + }() + + wg.Wait() + assert.Equal(t, 0, queue.Len()) +} + +func TestMsgQueue_EdgeCases(t *testing.T) { + // Test edge cases + queue := NewMsgQueue(1) + + // Test with nil message (if allowed by interface) + // This depends on the actual message.ImmutableMessage interface implementation + // For now, we'll test with valid messages + + // Test cleanup on empty queue + cleanedMessages := queue.CleanupConfirmedMessages(100) + assert.Equal(t, 0, queue.Len()) + assert.Nil(t, cleanedMessages) + + // Test seek to head on empty queue + queue.SeekToHead() + assert.Equal(t, 0, queue.readIdx) +} diff --git a/internal/cdc/replication/replicatestream/replicate_stream_client.go b/internal/cdc/replication/replicatestream/replicate_stream_client.go new file mode 100644 index 0000000000..ea1358791a --- /dev/null +++ b/internal/cdc/replication/replicatestream/replicate_stream_client.go @@ -0,0 +1,38 @@ +// Licensed to the LF AI & Data foundation under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The 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 replicatestream + +import ( + context "context" + + streamingpb "github.com/milvus-io/milvus/pkg/v2/proto/streamingpb" + "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" +) + +// ReplicateStreamClient is the client that replicates the message to the given cluster. +type ReplicateStreamClient interface { + // Replicate replicates the message to the target cluster. + // Replicate opeartion doesn't promise the message is delivered to the target cluster. + // It will cache the message in memory and retry until the message is delivered to the target cluster or the client is closed. + // Once the error is returned, the replicate operation will be unrecoverable. + Replicate(msg message.ImmutableMessage) error + + // Stop stops the replicate operation. + Close() +} + +type CreateReplicateStreamClientFunc func(ctx context.Context, replicateInfo *streamingpb.ReplicatePChannelMeta) ReplicateStreamClient diff --git a/internal/cdc/replication/replicatestream/replicate_stream_client_impl.go b/internal/cdc/replication/replicatestream/replicate_stream_client_impl.go new file mode 100644 index 0000000000..1c6a203a46 --- /dev/null +++ b/internal/cdc/replication/replicatestream/replicate_stream_client_impl.go @@ -0,0 +1,293 @@ +// Licensed to the LF AI & Data foundation under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The 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 replicatestream + +import ( + "context" + "sync" + "time" + + "github.com/cenkalti/backoff/v4" + "go.uber.org/zap" + + "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" + "github.com/milvus-io/milvus-proto/go-api/v2/milvuspb" + "github.com/milvus-io/milvus/internal/cdc/resource" + "github.com/milvus-io/milvus/internal/util/streamingutil/service/contextutil" + "github.com/milvus-io/milvus/pkg/v2/log" + "github.com/milvus-io/milvus/pkg/v2/proto/streamingpb" + "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" + "github.com/milvus-io/milvus/pkg/v2/util/paramtable" +) + +const pendingMessageQueueLength = 128 + +// replicateStreamClient is the implementation of ReplicateStreamClient. +type replicateStreamClient struct { + replicateInfo *streamingpb.ReplicatePChannelMeta + + clusterID string + client milvuspb.MilvusService_CreateReplicateStreamClient + pendingMessages MsgQueue + metrics ReplicateMetrics + + ctx context.Context + cancel context.CancelFunc + wg sync.WaitGroup +} + +// NewReplicateStreamClient creates a new ReplicateStreamClient. +func NewReplicateStreamClient(ctx context.Context, replicateInfo *streamingpb.ReplicatePChannelMeta) ReplicateStreamClient { + ctx1, cancel := context.WithCancel(ctx) + ctx1 = contextutil.WithClusterID(ctx1, replicateInfo.GetTargetCluster().GetClusterId()) + + rs := &replicateStreamClient{ + clusterID: paramtable.Get().CommonCfg.ClusterPrefix.GetValue(), + replicateInfo: replicateInfo, + pendingMessages: NewMsgQueue(pendingMessageQueueLength), + metrics: NewReplicateMetrics(replicateInfo), + ctx: ctx1, + cancel: cancel, + } + + rs.metrics.OnConnect() + go rs.startInternal() + return rs +} + +func (r *replicateStreamClient) startInternal() { + logger := log.With( + zap.String("sourceChannel", r.replicateInfo.GetSourceChannelName()), + zap.String("targetChannel", r.replicateInfo.GetTargetChannelName()), + ) + + defer func() { + r.metrics.OnDisconnect() + logger.Info("replicate stream client closed") + }() + + backoff := backoff.NewExponentialBackOff() + backoff.InitialInterval = 100 * time.Millisecond + backoff.MaxInterval = 10 * time.Second + backoff.MaxElapsedTime = 0 + backoff.Reset() + + disconnect := func(stopCh chan struct{}, err error) { + r.metrics.OnDisconnect() + close(stopCh) + r.client.CloseSend() + r.wg.Wait() + time.Sleep(backoff.NextBackOff()) + log.Warn("restart replicate stream client", zap.Error(err)) + } + + for { + select { + case <-r.ctx.Done(): + return + default: + milvusClient, err := resource.Resource().ClusterClient().CreateMilvusClient(r.ctx, r.replicateInfo.GetTargetCluster()) + if err != nil { + logger.Warn("create milvus client failed, retry...", zap.Error(err)) + time.Sleep(backoff.NextBackOff()) + continue + } + client, err := milvusClient.CreateReplicateStream(r.ctx) + if err != nil { + logger.Warn("create milvus replicate stream failed, retry...", zap.Error(err)) + time.Sleep(backoff.NextBackOff()) + continue + } + logger.Info("replicate stream client service started") + + // reset client and pending messages + if oldClient := r.client; oldClient != nil { + r.metrics.OnReconnect() + } + r.client = client + r.pendingMessages.SeekToHead() + + stopCh := make(chan struct{}) + sendErrCh := r.startSendLoop(stopCh) + recvErrCh := r.startRecvLoop(stopCh) + + select { + case <-r.ctx.Done(): + r.client.CloseSend() + r.wg.Wait() + return + case err := <-sendErrCh: + disconnect(stopCh, err) + case err := <-recvErrCh: + disconnect(stopCh, err) + } + } + } +} + +// Replicate replicates the message to the target cluster. +func (r *replicateStreamClient) Replicate(msg message.ImmutableMessage) error { + select { + case <-r.ctx.Done(): + return nil + default: + r.metrics.StartReplicate(msg) + r.pendingMessages.Enqueue(r.ctx, msg) + return nil + } +} + +func (r *replicateStreamClient) startSendLoop(stopCh <-chan struct{}) <-chan error { + errCh := make(chan error, 1) + r.wg.Add(1) + go func() { + defer r.wg.Done() + errCh <- r.sendLoop(stopCh) + }() + return errCh +} + +func (r *replicateStreamClient) startRecvLoop(stopCh <-chan struct{}) <-chan error { + errCh := make(chan error, 1) + r.wg.Add(1) + go func() { + defer r.wg.Done() + errCh <- r.recvLoop(stopCh) + }() + return errCh +} + +func (r *replicateStreamClient) sendLoop(stopCh <-chan struct{}) error { + logger := log.With( + zap.String("sourceChannel", r.replicateInfo.GetSourceChannelName()), + zap.String("targetChannel", r.replicateInfo.GetTargetChannelName()), + ) + for { + select { + case <-r.ctx.Done(): + logger.Info("send loop closed by ctx done") + return nil + case <-stopCh: + logger.Info("send loop closed by stopCh") + return nil + default: + msg, err := r.pendingMessages.Dequeue(r.ctx) + if err != nil { + // context canceled, return nil + return nil + } + if msg.MessageType() == message.MessageTypeTxn { + txnMsg := message.AsImmutableTxnMessage(msg) + + // send txn begin message + beginMsg := txnMsg.Begin() + err := r.sendMessage(beginMsg) + if err != nil { + return err + } + + // send txn messages + err = txnMsg.RangeOver(func(msg message.ImmutableMessage) error { + err = r.sendMessage(msg) + if err != nil { + return err + } + return nil + }) + if err != nil { + return err + } + + // send txn commit message + commitMsg := txnMsg.Commit() + err = r.sendMessage(commitMsg) + if err != nil { + return err + } + continue + } + err = r.sendMessage(msg) + if err != nil { + return err + } + } + } +} + +func (r *replicateStreamClient) sendMessage(msg message.ImmutableMessage) (err error) { + defer func() { + logger := log.With( + zap.String("sourceChannel", r.replicateInfo.GetSourceChannelName()), + zap.String("targetChannel", r.replicateInfo.GetTargetChannelName()), + ) + if err != nil { + logger.Warn("send message failed", zap.Error(err), log.FieldMessage(msg)) + } else { + r.metrics.OnSent(msg) + logger.Debug("send message success", log.FieldMessage(msg)) + } + }() + immutableMessage := msg.IntoImmutableMessageProto() + req := &milvuspb.ReplicateRequest{ + Request: &milvuspb.ReplicateRequest_ReplicateMessage{ + ReplicateMessage: &milvuspb.ReplicateMessage{ + SourceClusterId: r.clusterID, + Message: &commonpb.ImmutableMessage{ + Id: msg.MessageID().IntoProto(), + Payload: immutableMessage.GetPayload(), + Properties: immutableMessage.GetProperties(), + }, + }, + }, + } + return r.client.Send(req) +} + +func (r *replicateStreamClient) recvLoop(stopCh <-chan struct{}) error { + logger := log.With( + zap.String("sourceChannel", r.replicateInfo.GetSourceChannelName()), + zap.String("targetChannel", r.replicateInfo.GetTargetChannelName()), + ) + for { + select { + case <-r.ctx.Done(): + logger.Info("recv loop closed by ctx done") + return nil + case <-stopCh: + logger.Info("recv loop closed by stopCh") + return nil + default: + resp, err := r.client.Recv() + if err != nil { + logger.Warn("replicate stream recv failed", zap.Error(err)) + return err + } + lastConfirmedMessageInfo := resp.GetReplicateConfirmedMessageInfo() + if lastConfirmedMessageInfo != nil { + messages := r.pendingMessages.CleanupConfirmedMessages(lastConfirmedMessageInfo.GetConfirmedTimeTick()) + for _, msg := range messages { + r.metrics.OnConfirmed(msg) + } + } + } + } +} + +func (r *replicateStreamClient) Close() { + r.cancel() + r.wg.Wait() +} diff --git a/internal/cdc/replication/replicatestream/replicate_stream_client_impl_test.go b/internal/cdc/replication/replicatestream/replicate_stream_client_impl_test.go new file mode 100644 index 0000000000..d6b104a86d --- /dev/null +++ b/internal/cdc/replication/replicatestream/replicate_stream_client_impl_test.go @@ -0,0 +1,322 @@ +// Licensed to the LF AI & Data foundation under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The 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 replicatestream + +import ( + "context" + "strconv" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "google.golang.org/grpc" + "google.golang.org/grpc/metadata" + + "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" + milvuspb "github.com/milvus-io/milvus-proto/go-api/v2/milvuspb" + "github.com/milvus-io/milvus/internal/cdc/cluster" + "github.com/milvus-io/milvus/internal/cdc/resource" + "github.com/milvus-io/milvus/internal/distributed/streaming" + "github.com/milvus-io/milvus/internal/mocks/distributed/mock_streaming" + mock_message "github.com/milvus-io/milvus/pkg/v2/mocks/streaming/util/mock_message" + streamingpb "github.com/milvus-io/milvus/pkg/v2/proto/streamingpb" + message "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" + "github.com/milvus-io/milvus/pkg/v2/streaming/walimpls/impls/walimplstest" +) + +func TestReplicateStreamClient_Replicate(t *testing.T) { + ctx := context.Background() + targetCluster := &commonpb.MilvusCluster{ + ClusterId: "test-cluster", + ConnectionParam: &commonpb.ConnectionParam{ + Uri: "localhost:19530", + Token: "test-token", + }, + } + + // Setup mocks + mockStreamClient := newMockReplicateStreamClient(t) + + mockMilvusClient := cluster.NewMockMilvusClient(t) + mockMilvusClient.EXPECT().CreateReplicateStream(mock.Anything).Return(mockStreamClient, nil) + + mockClusterClient := cluster.NewMockClusterClient(t) + mockClusterClient.EXPECT().CreateMilvusClient(mock.Anything, mock.Anything). + Return(mockMilvusClient, nil) + + resource.InitForTest(t, + resource.OptClusterClient(mockClusterClient), + ) + + wal := mock_streaming.NewMockWALAccesser(t) + streaming.SetWALForTest(wal) + + replicateInfo := &streamingpb.ReplicatePChannelMeta{ + SourceChannelName: "test-source-channel", + TargetChannelName: "test-target-channel", + TargetCluster: targetCluster, + } + replicateClient := NewReplicateStreamClient(ctx, replicateInfo) + + // Test Replicate method + const msgCount = pendingMessageQueueLength * 10 + go func() { + for i := 0; i < msgCount; i++ { + mockMsg := mock_message.NewMockImmutableMessage(t) + tt := uint64(i + 1) + messageID := walimplstest.NewTestMessageID(int64(tt)) + mockMsg.EXPECT().TimeTick().Return(tt) + mockMsg.EXPECT().EstimateSize().Return(1024) + mockMsg.EXPECT().MessageType().Return(message.MessageTypeInsert) + mockMsg.EXPECT().MessageID().Return(messageID) + mockMsg.EXPECT().IntoImmutableMessageProto().Return(&commonpb.ImmutableMessage{ + Id: messageID.IntoProto(), + Payload: []byte("test-payload"), + Properties: map[string]string{"key": "value"}, + }) + mockMsg.EXPECT().MarshalLogObject(mock.Anything).Return(nil) + + err := replicateClient.Replicate(mockMsg) + assert.NoError(t, err) + } + }() + + // recv the confirm message + for i := 0; i < msgCount; i++ { + mockStreamClient.ExpectRecv() + } + assert.Equal(t, msgCount, mockStreamClient.GetRecvCount()) + assert.Equal(t, 0, replicateClient.(*replicateStreamClient).pendingMessages.Len()) + replicateClient.Close() +} + +func TestReplicateStreamClient_Replicate_ContextCanceled(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + targetCluster := &commonpb.MilvusCluster{ + ClusterId: "test-cluster", + ConnectionParam: &commonpb.ConnectionParam{ + Uri: "localhost:19530", + Token: "test-token", + }, + } + + // Setup mocks + mockStreamClient := newMockReplicateStreamClient(t) + mockMilvusClient := cluster.NewMockMilvusClient(t) + mockMilvusClient.EXPECT().CreateReplicateStream(mock.Anything).Return(mockStreamClient, nil).Maybe() + mockMilvusClient.EXPECT().Close(mock.Anything).Return(nil).Maybe() + + mockClusterClient := cluster.NewMockClusterClient(t) + mockClusterClient.EXPECT().CreateMilvusClient(mock.Anything, mock.Anything). + Return(mockMilvusClient, nil).Maybe() + + resource.InitForTest(t, + resource.OptClusterClient(mockClusterClient), + ) + + wal := mock_streaming.NewMockWALAccesser(t) + streaming.SetWALForTest(wal) + + replicateInfo := &streamingpb.ReplicatePChannelMeta{ + SourceChannelName: "test-source-channel", + TargetChannelName: "test-target-channel", + TargetCluster: targetCluster, + } + client := NewReplicateStreamClient(ctx, replicateInfo) + defer client.Close() + + // Cancel context + cancel() + + // Test Replicate method with canceled context + mockMsg := mock_message.NewMockImmutableMessage(t) + err := client.Replicate(mockMsg) + assert.NoError(t, err) // Should return nil when context is canceled +} + +func TestReplicateStreamClient_Reconnect(t *testing.T) { + ctx := context.Background() + targetCluster := &commonpb.MilvusCluster{ + ClusterId: "test-cluster", + ConnectionParam: &commonpb.ConnectionParam{ + Uri: "localhost:19530", + Token: "test-token", + }, + } + + const reconnectTimes = 3 + reconnectCount := 0 + // Setup mocks with error to trigger retry logic + mockStreamClient := newMockReplicateStreamClient(t) + mockMilvusClient := cluster.NewMockMilvusClient(t) + mockMilvusClient.EXPECT().CreateReplicateStream(mock.Anything).RunAndReturn(func(ctx context.Context, opts ...grpc.CallOption) (milvuspb.MilvusService_CreateReplicateStreamClient, error) { + reconnectCount++ + if reconnectCount < reconnectTimes { + return nil, assert.AnError + } + return mockStreamClient, nil + }).Times(reconnectTimes) // expect to be called reconnectTimes times + + mockClusterClient := cluster.NewMockClusterClient(t) + mockClusterClient.EXPECT().CreateMilvusClient(mock.Anything, mock.Anything). + Return(mockMilvusClient, nil) + + resource.InitForTest(t, + resource.OptClusterClient(mockClusterClient), + ) + + wal := mock_streaming.NewMockWALAccesser(t) + streaming.SetWALForTest(wal) + + // Create client which will start internal retry loop + replicateInfo := &streamingpb.ReplicatePChannelMeta{ + SourceChannelName: "test-source-channel", + TargetChannelName: "test-target-channel", + TargetCluster: targetCluster, + } + replicateClient := NewReplicateStreamClient(ctx, replicateInfo) + + // Replicate after reconnected + const msgCount = 100 + go func() { + for i := 0; i < msgCount; i++ { + tt := uint64(i + 1) + mockMsg := mock_message.NewMockImmutableMessage(t) + mockMsg.EXPECT().TimeTick().Return(tt) + messageID := walimplstest.NewTestMessageID(int64(tt)) + mockMsg.EXPECT().MessageID().Return(messageID) + mockMsg.EXPECT().EstimateSize().Return(1024) + mockMsg.EXPECT().MessageType().Return(message.MessageTypeInsert) + mockMsg.EXPECT().IntoImmutableMessageProto().Return(&commonpb.ImmutableMessage{ + Id: messageID.IntoProto(), + Payload: []byte("test-payload"), + Properties: map[string]string{"key": "value"}, + }) + mockMsg.EXPECT().MarshalLogObject(mock.Anything).Return(nil) + + err := replicateClient.Replicate(mockMsg) + assert.NoError(t, err) + } + }() + + for i := 0; i < msgCount; i++ { + mockStreamClient.ExpectRecv() + } + assert.Equal(t, msgCount, mockStreamClient.GetRecvCount()) + assert.Equal(t, 0, replicateClient.(*replicateStreamClient).pendingMessages.Len()) + replicateClient.Close() +} + +// mockReplicateStreamClient implements the milvuspb.MilvusService_CreateReplicateStreamClient interface +type mockReplicateStreamClient struct { + sendError error + recvError error + + ch chan *milvuspb.ReplicateRequest + expectRecvCh chan struct{} + recvCount int + + t *testing.T + timeout time.Duration + + closeCh chan struct{} +} + +func newMockReplicateStreamClient(t *testing.T) *mockReplicateStreamClient { + return &mockReplicateStreamClient{ + ch: make(chan *milvuspb.ReplicateRequest, 128), + expectRecvCh: make(chan struct{}, 128), + t: t, + timeout: 10 * time.Second, + closeCh: make(chan struct{}, 1), + } +} + +func (m *mockReplicateStreamClient) Send(req *milvuspb.ReplicateRequest) error { + if m.sendError != nil { + return m.sendError + } + m.ch <- req + return m.sendError +} + +func (m *mockReplicateStreamClient) Recv() (*milvuspb.ReplicateResponse, error) { + if m.recvError != nil { + return nil, m.recvError + } + select { + case <-m.closeCh: + return nil, nil + case req := <-m.ch: + // use id as time tick in mock + timeTick, err := strconv.ParseUint(req.GetReplicateMessage().GetMessage().GetId().GetId(), 10, 64) + if err != nil { + panic(err) + } + m.expectRecvCh <- struct{}{} + return &milvuspb.ReplicateResponse{ + Response: &milvuspb.ReplicateResponse_ReplicateConfirmedMessageInfo{ + ReplicateConfirmedMessageInfo: &milvuspb.ReplicateConfirmedMessageInfo{ + ConfirmedTimeTick: timeTick, + }, + }, + }, nil + case <-time.After(m.timeout): + assert.Fail(m.t, "recv timeout") + return nil, assert.AnError + } +} + +func (m *mockReplicateStreamClient) ExpectRecv() { + select { + case <-m.expectRecvCh: + m.recvCount++ + return + case <-time.After(m.timeout): + assert.Fail(m.t, "expect recv timeout") + } +} + +func (m *mockReplicateStreamClient) GetRecvCount() int { + return m.recvCount +} + +func (m *mockReplicateStreamClient) RecvMsg(msg interface{}) error { + return nil +} + +func (m *mockReplicateStreamClient) SendMsg(msg interface{}) error { + return nil +} + +func (m *mockReplicateStreamClient) Header() (metadata.MD, error) { + return nil, nil +} + +func (m *mockReplicateStreamClient) Trailer() metadata.MD { + return nil +} + +func (m *mockReplicateStreamClient) CloseSend() error { + close(m.closeCh) + return nil +} + +func (m *mockReplicateStreamClient) Context() context.Context { + return context.Background() +} diff --git a/internal/cdc/resource/resource.go b/internal/cdc/resource/resource.go new file mode 100644 index 0000000000..8b323482ed --- /dev/null +++ b/internal/cdc/resource/resource.go @@ -0,0 +1,143 @@ +// Licensed to the LF AI & Data foundation under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The 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 resource + +import ( + "reflect" + + "github.com/milvus-io/milvus/internal/cdc/cluster" + "github.com/milvus-io/milvus/internal/cdc/controller" + "github.com/milvus-io/milvus/internal/cdc/replication" + "github.com/milvus-io/milvus/internal/metastore" + "github.com/milvus-io/milvus/internal/metastore/kv/streamingcoord" + "github.com/milvus-io/milvus/pkg/v2/kv" +) + +var r *resourceImpl // singleton resource instance + +// optResourceInit is the option to initialize the resource. +type optResourceInit func(r *resourceImpl) + +// OptMetaKV provides the meta kv to the resource. +func OptMetaKV(metaKV kv.MetaKv) optResourceInit { + return func(r *resourceImpl) { + r.metaKV = metaKV + } +} + +// OptReplicateManagerClient provides the replicate manager client to the resource. +func OptReplicateManagerClient(replicateManagerClient replication.ReplicateManagerClient) optResourceInit { + return func(r *resourceImpl) { + r.replicateManagerClient = replicateManagerClient + } +} + +// OptReplicationCatalog provides the replication catalog to the resource. +func OptReplicationCatalog(catalog metastore.ReplicationCatalog) optResourceInit { + return func(r *resourceImpl) { + r.catalog = catalog + } +} + +// OptClusterClient provides the cluster client to the resource. +func OptClusterClient(clusterClient cluster.ClusterClient) optResourceInit { + return func(r *resourceImpl) { + r.clusterClient = clusterClient + } +} + +// OptController provides the controller to the resource. +func OptController(controller controller.Controller) optResourceInit { + return func(r *resourceImpl) { + r.controller = controller + } +} + +// Done finish all initialization of resources. +func Init(opts ...optResourceInit) { + newR := &resourceImpl{} + for _, opt := range opts { + opt(newR) + } + + newR.catalog = streamingcoord.NewReplicationCatalog(newR.MetaKV()) + newR.clusterClient = cluster.NewClusterClient() + + assertNotNil(newR.MetaKV()) + assertNotNil(newR.ReplicationCatalog()) + assertNotNil(newR.ClusterClient()) + assertNotNil(newR.ReplicateManagerClient()) + assertNotNil(newR.Controller()) + r = newR +} + +// Release releases the singleton of resources. +func Release() {} + +// Resource access the underlying singleton of resources. +func Resource() *resourceImpl { + return r +} + +// resourceImpl is a basic resource dependency for streamingnode server. +// All utility on it is concurrent-safe and singleton. +type resourceImpl struct { + metaKV kv.MetaKv + catalog metastore.ReplicationCatalog + clusterClient cluster.ClusterClient + replicateManagerClient replication.ReplicateManagerClient + controller controller.Controller +} + +// MetaKV returns the meta kv. +func (r *resourceImpl) MetaKV() kv.MetaKv { + return r.metaKV +} + +// ReplicationCatalog returns the replication catalog. +func (r *resourceImpl) ReplicationCatalog() metastore.ReplicationCatalog { + return r.catalog +} + +// ClusterClient returns the cluster client. +func (r *resourceImpl) ClusterClient() cluster.ClusterClient { + return r.clusterClient +} + +// ReplicateManagerClient returns the replicate manager client. +func (r *resourceImpl) ReplicateManagerClient() replication.ReplicateManagerClient { + return r.replicateManagerClient +} + +// Controller returns the controller. +func (r *resourceImpl) Controller() controller.Controller { + return r.controller +} + +// assertNotNil panics if the resource is nil. +func assertNotNil(v interface{}) { + iv := reflect.ValueOf(v) + if !iv.IsValid() { + panic("nil resource") + } + switch iv.Kind() { + case reflect.Ptr, reflect.Slice, reflect.Map, reflect.Func, reflect.Interface: + if iv.IsNil() { + panic("nil resource") + } + } +} diff --git a/internal/cdc/resource/test_utility.go b/internal/cdc/resource/test_utility.go new file mode 100644 index 0000000000..6afeba097a --- /dev/null +++ b/internal/cdc/resource/test_utility.go @@ -0,0 +1,37 @@ +//go:build test +// +build test + +package resource + +import ( + "testing" + + "github.com/milvus-io/milvus/internal/cdc/cluster" + "github.com/milvus-io/milvus/internal/cdc/controller" + "github.com/milvus-io/milvus/internal/cdc/replication" + "github.com/milvus-io/milvus/internal/mocks/mock_metastore" + "github.com/milvus-io/milvus/pkg/v2/mocks/mock_kv" +) + +// InitForTest initializes the singleton of resources for test. +func InitForTest(t *testing.T, opts ...optResourceInit) { + r = &resourceImpl{} + for _, opt := range opts { + opt(r) + } + if r.metaKV == nil { + r.metaKV = mock_kv.NewMockMetaKv(t) + } + if r.catalog == nil { + r.catalog = mock_metastore.NewMockReplicationCatalog(t) + } + if r.clusterClient == nil { + r.clusterClient = cluster.NewMockClusterClient(t) + } + if r.replicateManagerClient == nil { + r.replicateManagerClient = replication.NewMockReplicateManagerClient(t) + } + if r.controller == nil { + r.controller = controller.NewMockController(t) + } +} diff --git a/internal/cdc/server.go b/internal/cdc/server.go new file mode 100644 index 0000000000..315c944a03 --- /dev/null +++ b/internal/cdc/server.go @@ -0,0 +1,55 @@ +// Licensed to the LF AI & Data foundation under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The 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 cdc + +import ( + "context" + + "github.com/milvus-io/milvus/internal/cdc/resource" + "github.com/milvus-io/milvus/pkg/v2/log" +) + +type CDCServer struct { + ctx context.Context +} + +// NewCDCServer will return a CDCServer. +func NewCDCServer(ctx context.Context) *CDCServer { + return &CDCServer{ + ctx: ctx, + } +} + +// Init initializes the CDCServer. +func (svr *CDCServer) Init() error { + log.Ctx(svr.ctx).Info("CDCServer init successfully") + return nil +} + +// Start starts CDCServer. +func (svr *CDCServer) Start() error { + resource.Resource().Controller().Start() + log.Ctx(svr.ctx).Info("CDCServer start successfully") + return nil +} + +// Stop stops CDCServer. +func (svr *CDCServer) Stop() error { + resource.Resource().Controller().Stop() + log.Ctx(svr.ctx).Info("CDCServer stop successfully") + return nil +} diff --git a/internal/datacoord/session/mock_node_manager.go b/internal/datacoord/session/mock_node_manager.go index b30096e46b..5a494237a4 100644 --- a/internal/datacoord/session/mock_node_manager.go +++ b/internal/datacoord/session/mock_node_manager.go @@ -259,8 +259,7 @@ func (_c *MockNodeManager_Startup_Call) RunAndReturn(run func(context.Context, [ func NewMockNodeManager(t interface { mock.TestingT Cleanup(func()) -}, -) *MockNodeManager { +}) *MockNodeManager { mock := &MockNodeManager{} mock.Mock.Test(t) diff --git a/internal/distributed/cdc/service.go b/internal/distributed/cdc/service.go new file mode 100644 index 0000000000..7fa773b798 --- /dev/null +++ b/internal/distributed/cdc/service.go @@ -0,0 +1,194 @@ +// Licensed to the LF AI & Data foundation under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The 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 cdc + +import ( + "context" + "sync" + "time" + + "github.com/tikv/client-go/v2/txnkv" + clientv3 "go.etcd.io/etcd/client/v3" + "go.uber.org/zap" + + "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" + "github.com/milvus-io/milvus-proto/go-api/v2/milvuspb" + "github.com/milvus-io/milvus/internal/cdc" + "github.com/milvus-io/milvus/internal/cdc/controller/controllerimpl" + "github.com/milvus-io/milvus/internal/cdc/replication/replicatemanager" + "github.com/milvus-io/milvus/internal/cdc/resource" + etcdkv "github.com/milvus-io/milvus/internal/kv/etcd" + tikvkv "github.com/milvus-io/milvus/internal/kv/tikv" + "github.com/milvus-io/milvus/internal/util/componentutil" + kvfactory "github.com/milvus-io/milvus/internal/util/dependency/kv" + "github.com/milvus-io/milvus/pkg/v2/kv" + "github.com/milvus-io/milvus/pkg/v2/log" + "github.com/milvus-io/milvus/pkg/v2/util" + "github.com/milvus-io/milvus/pkg/v2/util/paramtable" + "github.com/milvus-io/milvus/pkg/v2/util/tikv" + "github.com/milvus-io/milvus/pkg/v2/util/typeutil" +) + +// Server is the server of cdc. +type Server struct { + ctx context.Context + cancel context.CancelFunc + + metaKV kv.MetaKv + cdcServer *cdc.CDCServer + + etcdCli *clientv3.Client + tikvCli *txnkv.Client + + componentState *componentutil.ComponentStateService + stopOnce sync.Once +} + +// NewServer create a new CDC server. +func NewServer(ctx context.Context) (*Server, error) { + ctx1, cancel := context.WithCancel(ctx) + return &Server{ + ctx: ctx1, + cancel: cancel, + componentState: componentutil.NewComponentStateService(typeutil.CDCRole), + stopOnce: sync.Once{}, + }, nil +} + +func (s *Server) Prepare() error { + return nil +} + +// Run runs the server. +func (s *Server) Run() error { + if err := s.init(); err != nil { + return err + } + log.Ctx(s.ctx).Info("cdc init done") + + if err := s.start(); err != nil { + return err + } + log.Ctx(s.ctx).Info("cdc start done") + return nil +} + +// Stop stops the server, should be call after Run returned. +func (s *Server) Stop() (err error) { + s.stopOnce.Do(s.stop) + return nil +} + +// stop stops the server. +func (s *Server) stop() { + s.componentState.OnStopping() + log := log.Ctx(s.ctx) + + log.Info("stopping cdc...") + + // Stop CDC service. + s.cdcServer.Stop() + + // Stop etcd + if s.etcdCli != nil { + if err := s.etcdCli.Close(); err != nil { + log.Warn("cdc stop etcd client failed", zap.Error(err)) + } + } + + // Stop tikv + if s.tikvCli != nil { + if err := s.tikvCli.Close(); err != nil { + log.Warn("cdc stop tikv client failed", zap.Error(err)) + } + } + + log.Info("cdc stop done") +} + +// Health check the health status of cdc. +func (s *Server) Health(ctx context.Context) commonpb.StateCode { + resp, _ := s.componentState.GetComponentStates(ctx, &milvuspb.GetComponentStatesRequest{}) + return resp.GetState().StateCode +} + +func (s *Server) init() (err error) { + log := log.Ctx(s.ctx) + defer func() { + if err != nil { + log.Error("cdc init failed", zap.Error(err)) + return + } + log.Info("init cdc server finished") + }() + + // Create etcd client. + s.etcdCli, _ = kvfactory.GetEtcdAndPath() + + if err := s.initMeta(); err != nil { + return err + } + + // Create CDC service. + s.cdcServer = cdc.NewCDCServer(s.ctx) + resource.Init( + resource.OptMetaKV(s.metaKV), + resource.OptReplicateManagerClient(replicatemanager.NewReplicateManager()), + resource.OptController(controllerimpl.NewController()), + ) + return nil +} + +func (s *Server) start() (err error) { + log := log.Ctx(s.ctx) + defer func() { + if err != nil { + log.Error("CDC start failed", zap.Error(err)) + return + } + log.Info("start CDC server finished") + }() + + s.cdcServer.Start() + + s.componentState.OnInitialized(0) + return nil +} + +func (s *Server) initMeta() error { + params := paramtable.Get() + metaType := params.MetaStoreCfg.MetaStoreType.GetValue() + log := log.Ctx(s.ctx) + log.Info("cdc connecting to metadata store", zap.String("metaType", metaType)) + metaRootPath := "" + if metaType == util.MetaStoreTypeTiKV { + var err error + s.tikvCli, err = tikv.GetTiKVClient(¶mtable.Get().TiKVCfg) + if err != nil { + log.Warn("cdc init tikv client failed", zap.Error(err)) + return err + } + metaRootPath = params.TiKVCfg.MetaRootPath.GetValue() + s.metaKV = tikvkv.NewTiKV(s.tikvCli, metaRootPath, + tikvkv.WithRequestTimeout(paramtable.Get().ServiceParam.TiKVCfg.RequestTimeout.GetAsDuration(time.Millisecond))) + } else if metaType == util.MetaStoreTypeEtcd { + metaRootPath = params.EtcdCfg.MetaRootPath.GetValue() + s.metaKV = etcdkv.NewEtcdKV(s.etcdCli, metaRootPath, + etcdkv.WithRequestTimeout(paramtable.Get().ServiceParam.EtcdCfg.RequestTimeout.GetAsDuration(time.Millisecond))) + } + return nil +} diff --git a/internal/distributed/proxy/service.go b/internal/distributed/proxy/service.go index 7d1ca86f55..f4a4f5e63a 100644 --- a/internal/distributed/proxy/service.go +++ b/internal/distributed/proxy/service.go @@ -1149,3 +1149,18 @@ func (s *Server) RemoveFileResource(ctx context.Context, req *milvuspb.RemoveFil func (s *Server) ListFileResources(ctx context.Context, req *milvuspb.ListFileResourcesRequest) (*milvuspb.ListFileResourcesResponse, error) { return s.proxy.ListFileResources(ctx, req) } + +// UpdateReplicateConfiguration applies a full replacement of the current replication configuration across Milvus clusters. +func (s *Server) UpdateReplicateConfiguration(ctx context.Context, req *milvuspb.UpdateReplicateConfigurationRequest) (*commonpb.Status, error) { + return s.proxy.UpdateReplicateConfiguration(ctx, req) +} + +// GetReplicateInfo retrieves replication-related metadata from a target Milvus cluster. +func (s *Server) GetReplicateInfo(ctx context.Context, req *milvuspb.GetReplicateInfoRequest) (*milvuspb.GetReplicateInfoResponse, error) { + return s.proxy.GetReplicateInfo(ctx, req) +} + +// CreateReplicateStream establishes a replication stream on the target Milvus cluster. +func (s *Server) CreateReplicateStream(stream milvuspb.MilvusService_CreateReplicateStreamServer) error { + return s.proxy.CreateReplicateStream(stream) +} diff --git a/internal/distributed/streaming/append.go b/internal/distributed/streaming/append.go index 0897cb3737..d9db727c1e 100644 --- a/internal/distributed/streaming/append.go +++ b/internal/distributed/streaming/append.go @@ -39,6 +39,9 @@ func assertValidMessage(msgs ...message.MutableMessage) { if msg.MessageType().IsSystem() { panic("system message is not allowed to append from client") } + if msg.MessageType().IsSelfControlled() { + panic("self controlled message is not allowed to append from client") + } if msg.VChannel() == "" { panic("we don't support sent all vchannel message at client now") } @@ -50,6 +53,9 @@ func assertValidBroadcastMessage(msg message.BroadcastMutableMessage) { if msg.MessageType().IsSystem() { panic("system message is not allowed to broadcast append from client") } + if msg.MessageType().IsSelfControlled() { + panic("self controlled message is not allowed to broadcast append from client") + } } // We only support delete and insert message for txn now. diff --git a/internal/distributed/streaming/internal/errs/error.go b/internal/distributed/streaming/internal/errs/error.go index bc6f62c3c4..c1726fbb19 100644 --- a/internal/distributed/streaming/internal/errs/error.go +++ b/internal/distributed/streaming/internal/errs/error.go @@ -10,4 +10,5 @@ var ( ErrCanceledOrDeadlineExceed = errors.New("canceled or deadline exceed") ErrUnrecoverable = errors.New("unrecoverable") ErrFenced = errors.New("fenced") + ErrIgnoredOperation = errors.New("ignored operation") ) diff --git a/internal/distributed/streaming/internal/producer/producer.go b/internal/distributed/streaming/internal/producer/producer.go index 816a7db983..594e279710 100644 --- a/internal/distributed/streaming/internal/producer/producer.go +++ b/internal/distributed/streaming/internal/producer/producer.go @@ -105,6 +105,9 @@ func (p *ResumableProducer) Produce(ctx context.Context, msg message.MutableMess if sErr.IsUnrecoverable() { return nil, errors.Mark(err, errs.ErrUnrecoverable) } + if sErr.IsIgnoredOperation() { + return nil, errors.Mark(err, errs.ErrIgnoredOperation) + } } } } diff --git a/internal/distributed/streaming/msgstream_adaptor.go b/internal/distributed/streaming/msgstream_adaptor.go index d6ffe68ab1..6ebd02bdd0 100644 --- a/internal/distributed/streaming/msgstream_adaptor.go +++ b/internal/distributed/streaming/msgstream_adaptor.go @@ -95,7 +95,7 @@ func (m *delegatorMsgstreamAdaptor) Seek(ctx context.Context, msgPositions []*ms panic("should never be called if len(msgPositions) is not 1") } position := msgPositions[0] - startFrom := adaptor.MustGetMessageIDFromMQWrapperIDBytes(WAL().WALName(), position.MsgID) + startFrom := adaptor.MustGetMessageIDFromMQWrapperIDBytes(position.MsgID) log.Info( "delegator msgstream adaptor seeks from position with scanner", zap.String("channel", position.GetChannelName()), diff --git a/internal/distributed/streaming/replicate_service.go b/internal/distributed/streaming/replicate_service.go new file mode 100644 index 0000000000..0b63ffcad3 --- /dev/null +++ b/internal/distributed/streaming/replicate_service.go @@ -0,0 +1,149 @@ +package streaming + +import ( + "context" + "strings" + + "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" + "github.com/milvus-io/milvus/internal/streamingnode/server/wal" + "github.com/milvus-io/milvus/internal/util/streamingutil/status" + "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" + "github.com/milvus-io/milvus/pkg/v2/streaming/util/types" + "github.com/milvus-io/milvus/pkg/v2/util/funcutil" + "github.com/milvus-io/milvus/pkg/v2/util/replicateutil" + "github.com/milvus-io/milvus/pkg/v2/util/typeutil" +) + +var _ ReplicateService = replicateService{} + +type replicateService struct { + *walAccesserImpl +} + +// Append appends the message into current cluster. +func (s replicateService) Append(ctx context.Context, rmsg message.ReplicateMutableMessage) (*types.AppendResult, error) { + rh := rmsg.ReplicateHeader() + if rh == nil { + panic("message is not a replicate message") + } + + if !s.lifetime.Add(typeutil.LifetimeStateWorking) { + return nil, ErrWALAccesserClosed + } + defer s.lifetime.Done() + + msg, err := s.overwriteReplicateMessage(ctx, rmsg, rh) + if err != nil { + return nil, err + } + return s.appendToWAL(ctx, msg) +} + +func (s replicateService) UpdateReplicateConfiguration(ctx context.Context, config *commonpb.ReplicateConfiguration) error { + if !s.lifetime.Add(typeutil.LifetimeStateWorking) { + return ErrWALAccesserClosed + } + defer s.lifetime.Done() + + return s.streamingCoordClient.Assignment().UpdateReplicateConfiguration(ctx, config) +} + +func (s replicateService) GetReplicateConfiguration(ctx context.Context) (*replicateutil.ConfigHelper, error) { + if !s.lifetime.Add(typeutil.LifetimeStateWorking) { + return nil, ErrWALAccesserClosed + } + defer s.lifetime.Done() + + config, err := s.streamingCoordClient.Assignment().GetReplicateConfiguration(ctx) + if err != nil { + return nil, err + } + return config, nil +} + +func (s replicateService) GetReplicateCheckpoint(ctx context.Context, channelName string) (*wal.ReplicateCheckpoint, error) { + if !s.lifetime.Add(typeutil.LifetimeStateWorking) { + return nil, ErrWALAccesserClosed + } + defer s.lifetime.Done() + + checkpoint, err := s.handlerClient.GetReplicateCheckpoint(ctx, channelName) + if err != nil { + return nil, err + } + + return checkpoint, nil +} + +// overwriteReplicateMessage overwrites the replicate message. +// because some message such as create collection message write vchannel in its body, so we need to overwrite the message. +func (s replicateService) overwriteReplicateMessage(ctx context.Context, msg message.ReplicateMutableMessage, rh *message.ReplicateHeader) (message.MutableMessage, error) { + cfg, err := s.streamingCoordClient.Assignment().GetReplicateConfiguration(ctx) + if err != nil { + return nil, err + } + + // Get target vchannel on current cluster that should be written to + currentCluster := cfg.GetCluster(s.clusterID) + if currentCluster.Role() == replicateutil.RolePrimary { + return nil, status.NewReplicateViolation("primary cluster cannot receive replicate message") + } + sourceCluster := cfg.GetCluster(rh.ClusterID) + if sourceCluster == nil { + return nil, status.NewReplicateViolation("source cluster %s not found in replicate configuration", rh.ClusterID) + } + targetVChannel, err := s.getTargetVChannel(sourceCluster, msg.VChannel()) + if err != nil { + return nil, err + } + + // Get target broadcast vchannels on current cluster that should be written to + if bh := msg.BroadcastHeader(); bh != nil { + // broadcast header have vchannels, so we need to overwrite it. + targetBroadcastVChannels := make([]string, 0, len(bh.VChannels)) + for _, vchannel := range bh.VChannels { + targetBroadcastVChannel, err := s.getTargetVChannel(sourceCluster, vchannel) + if err != nil { + return nil, status.NewReplicateViolation("failed to get target channel, %s", err.Error()) + } + targetBroadcastVChannels = append(targetBroadcastVChannels, targetBroadcastVChannel) + } + msg.OverwriteReplicateVChannel(targetVChannel, targetBroadcastVChannels) + } else { + msg.OverwriteReplicateVChannel(targetVChannel) + } + + // create collection message will set the vchannel in its body, so we need to overwrite it. + if msg.MessageType() == message.MessageTypeCreateCollection { + if err := s.overwriteCreateCollectionMessage(sourceCluster, msg); err != nil { + return nil, err + } + } + return msg, nil +} + +// getTargetVChannel gets the target vchannel of the source vchannel. +func (s replicateService) getTargetVChannel(sourceCluster *replicateutil.MilvusCluster, sourceVChannel string) (string, error) { + sourcePChannel := funcutil.ToPhysicalChannel(sourceVChannel) + targetPChannel, err := sourceCluster.GetTargetChannel(sourcePChannel, s.clusterID) + if err != nil { + return "", status.NewReplicateViolation("failed to get target channel, %s", err.Error()) + } + return strings.Replace(sourceVChannel, sourcePChannel, targetPChannel, 1), nil +} + +// overwriteCreateCollectionMessage overwrites the create collection message. +func (s replicateService) overwriteCreateCollectionMessage(sourceCluster *replicateutil.MilvusCluster, msg message.ReplicateMutableMessage) error { + createCollectionMsg := message.MustAsMutableCreateCollectionMessageV1(msg) + body := createCollectionMsg.MustBody() + for idx, sourcePChannel := range body.PhysicalChannelNames { + targetPChannel, err := sourceCluster.GetTargetChannel(sourcePChannel, s.clusterID) + if err != nil { + return status.NewReplicateViolation("failed to get target channel, %s", err.Error()) + } + body.PhysicalChannelNames[idx] = targetPChannel + body.VirtualChannelNames[idx] = strings.Replace(body.VirtualChannelNames[idx], sourcePChannel, targetPChannel, 1) + } + createCollectionMsg.OverwriteBody(body) + return nil +} diff --git a/internal/distributed/streaming/replicate_service_test.go b/internal/distributed/streaming/replicate_service_test.go new file mode 100644 index 0000000000..cf49368cd2 --- /dev/null +++ b/internal/distributed/streaming/replicate_service_test.go @@ -0,0 +1,124 @@ +package streaming + +import ( + "context" + "strings" + "testing" + + "github.com/apache/pulsar-client-go/pulsar" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "google.golang.org/protobuf/proto" + + "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" + "github.com/milvus-io/milvus-proto/go-api/v2/msgpb" + "github.com/milvus-io/milvus-proto/go-api/v2/schemapb" + "github.com/milvus-io/milvus/internal/distributed/streaming/internal/producer" + "github.com/milvus-io/milvus/internal/mocks/streamingcoord/mock_client" + "github.com/milvus-io/milvus/internal/mocks/streamingnode/client/handler/mock_producer" + "github.com/milvus-io/milvus/internal/mocks/streamingnode/client/mock_handler" + "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" + "github.com/milvus-io/milvus/pkg/v2/streaming/util/types" + pulsar2 "github.com/milvus-io/milvus/pkg/v2/streaming/walimpls/impls/pulsar" + "github.com/milvus-io/milvus/pkg/v2/streaming/walimpls/impls/walimplstest" + "github.com/milvus-io/milvus/pkg/v2/util/replicateutil" + "github.com/milvus-io/milvus/pkg/v2/util/typeutil" +) + +func TestReplicateService(t *testing.T) { + c := mock_client.NewMockClient(t) + as := mock_client.NewMockAssignmentService(t) + c.EXPECT().Assignment().Return(as).Maybe() + + h := mock_handler.NewMockHandlerClient(t) + p := mock_producer.NewMockProducer(t) + p.EXPECT().Append(mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, mm message.MutableMessage) (*types.AppendResult, error) { + msg := message.MustAsMutableCreateCollectionMessageV1(mm) + assert.True(t, strings.HasPrefix(msg.VChannel(), "by-dev")) + for _, vchannel := range msg.BroadcastHeader().VChannels { + assert.True(t, strings.HasPrefix(vchannel, "by-dev")) + } + b := msg.MustBody() + for _, vchannel := range b.VirtualChannelNames { + assert.True(t, strings.HasPrefix(vchannel, "by-dev")) + } + for _, pchannel := range b.PhysicalChannelNames { + assert.True(t, strings.HasPrefix(pchannel, "by-dev")) + } + return &types.AppendResult{ + MessageID: walimplstest.NewTestMessageID(1), + TimeTick: 1, + }, nil + }).Maybe() + p.EXPECT().IsAvailable().Return(true).Maybe() + p.EXPECT().Available().Return(make(chan struct{})).Maybe() + h.EXPECT().CreateProducer(mock.Anything, mock.Anything).Return(p, nil).Maybe() + + as.EXPECT().GetReplicateConfiguration(mock.Anything).Return(replicateutil.MustNewConfigHelper( + "by-dev", + &commonpb.ReplicateConfiguration{ + Clusters: []*commonpb.MilvusCluster{ + {ClusterId: "primary", Pchannels: []string{"primary-rootcoord-dml_0", "primary-rootcoord-dml_1"}}, + {ClusterId: "by-dev", Pchannels: []string{"by-dev-rootcoord-dml_0", "by-dev-rootcoord-dml_1"}}, + }, + CrossClusterTopology: []*commonpb.CrossClusterTopology{ + {SourceClusterId: "primary", TargetClusterId: "by-dev"}, + }, + }, + ), nil) + rs := &replicateService{ + walAccesserImpl: &walAccesserImpl{ + lifetime: typeutil.NewLifetime(), + clusterID: "by-dev", + streamingCoordClient: c, + handlerClient: h, + producers: make(map[string]*producer.ResumableProducer), + }, + } + replicateMsgs := createReplicateCreateCollectionMessages() + + for _, msg := range replicateMsgs { + _, err := rs.Append(context.Background(), msg) + assert.NoError(t, err) + } +} + +func createReplicateCreateCollectionMessages() []message.ReplicateMutableMessage { + schema := &schemapb.CollectionSchema{ + Fields: []*schemapb.FieldSchema{ + {FieldID: 100, Name: "ID", IsPrimaryKey: true, DataType: schemapb.DataType_Int64}, + {FieldID: 101, Name: "Vector", DataType: schemapb.DataType_FloatVector}, + }, + } + schemaBytes, _ := proto.Marshal(schema) + msg := message.NewCreateCollectionMessageBuilderV1(). + WithHeader(&message.CreateCollectionMessageHeader{ + CollectionId: 1, + PartitionIds: []int64{2}, + }). + WithBody(&msgpb.CreateCollectionRequest{ + CollectionID: 1, + CollectionName: "collection", + PartitionName: "partition", + PhysicalChannelNames: []string{ + "primary-rootcoord-dml_0", + "primary-rootcoord-dml_1", + }, + VirtualChannelNames: []string{ + "primary-rootcoord-dml_0_1v0", + "primary-rootcoord-dml_1_1v1", + }, + Schema: schemaBytes, + }). + WithBroadcast([]string{"primary-rootcoord-dml_0_1v0", "primary-rootcoord-dml_1_1v1"}). + MustBuildBroadcast() + msgs := msg.WithBroadcastID(100).SplitIntoMutableMessage() + replicateMsgs := make([]message.ReplicateMutableMessage, 0, len(msgs)) + for _, msg := range msgs { + immutableMsg := msg.WithLastConfirmedUseMessageID().WithTimeTick(1).IntoImmutableMessage(pulsar2.NewPulsarID( + pulsar.NewMessageID(1, 2, 3, 4), + )) + replicateMsgs = append(replicateMsgs, message.NewReplicateMessage("primary", immutableMsg.IntoImmutableMessageProto())) + } + return replicateMsgs +} diff --git a/internal/distributed/streaming/streaming.go b/internal/distributed/streaming/streaming.go index 3527470338..123760eabe 100644 --- a/internal/distributed/streaming/streaming.go +++ b/internal/distributed/streaming/streaming.go @@ -4,10 +4,15 @@ import ( "context" "time" + "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" + "github.com/milvus-io/milvus/internal/streamingnode/server/wal" kvfactory "github.com/milvus-io/milvus/internal/util/dependency/kv" + "github.com/milvus-io/milvus/internal/util/hookutil" + "github.com/milvus-io/milvus/internal/util/streamingutil/util" "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" "github.com/milvus-io/milvus/pkg/v2/streaming/util/options" "github.com/milvus-io/milvus/pkg/v2/streaming/util/types" + "github.com/milvus-io/milvus/pkg/v2/util/replicateutil" ) var singleton WALAccesser = nil @@ -16,6 +21,12 @@ var singleton WALAccesser = nil // should be called before any other operations. func Init() { c, _ := kvfactory.GetEtcdAndPath() + // init and select wal name + util.InitAndSelectWALName() + // register cipher for cipher message + if hookutil.IsClusterEncyptionEnabled() { + message.RegisterCipher(hookutil.GetCipher()) + } singleton = newWALAccesser(c) } @@ -81,6 +92,22 @@ type Scanner interface { Close() } +// ReplicateService is the interface for the replicate service. +type ReplicateService interface { + // Append appends the message into current cluster. + Append(ctx context.Context, msg message.ReplicateMutableMessage) (*types.AppendResult, error) + + // UpdateReplicateConfiguration updates the replicate configuration to the milvus cluster. + UpdateReplicateConfiguration(ctx context.Context, config *commonpb.ReplicateConfiguration) error + + // GetReplicateConfiguration returns the replicate configuration of the milvus cluster. + GetReplicateConfiguration(ctx context.Context) (*replicateutil.ConfigHelper, error) + + // GetReplicateCheckpoint returns the WAL checkpoint that will be used to create scanner + // from the correct position, ensuring no duplicate or missing messages. + GetReplicateCheckpoint(ctx context.Context, channelName string) (*wal.ReplicateCheckpoint, error) +} + // Balancer is the interface for managing the balancer of the wal. type Balancer interface { // ListStreamingNode lists the streaming node. @@ -108,6 +135,9 @@ type Balancer interface { // WALAccesser is the interfaces to interact with the milvus write ahead log. type WALAccesser interface { + // Replicate returns the replicate service of the wal. + Replicate() ReplicateService + // ControlChannel returns the control channel name of the wal. // It will return the channel name of the control channel of the wal. ControlChannel() string @@ -115,9 +145,6 @@ type WALAccesser interface { // Balancer returns the balancer management of the wal. Balancer() Balancer - // WALName returns the name of the wal. - WALName() string - // Local returns the local services. Local() Local diff --git a/internal/distributed/streaming/streaming_test.go b/internal/distributed/streaming/streaming_test.go index 52760628af..33e9ca9ce1 100644 --- a/internal/distributed/streaming/streaming_test.go +++ b/internal/distributed/streaming/streaming_test.go @@ -16,7 +16,6 @@ import ( "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" "github.com/milvus-io/milvus/pkg/v2/streaming/util/message/adaptor" "github.com/milvus-io/milvus/pkg/v2/streaming/util/options" - _ "github.com/milvus-io/milvus/pkg/v2/streaming/walimpls/impls/pulsar" "github.com/milvus-io/milvus/pkg/v2/util/paramtable" ) @@ -33,6 +32,56 @@ func TestMain(m *testing.M) { m.Run() } +func TestReplicate(t *testing.T) { + t.Skip("cat not running without streaming service at background") + + streaming.Init() + defer streaming.Release() + + pchannels1 := make([]string, 0, len(vChannels)) + pchannels2 := make([]string, 0, len(vChannels)) + for idx := 0; idx < 16; idx++ { + pchannels1 = append(pchannels1, fmt.Sprintf("primary-rootcoord-dml_%d", idx)) + pchannels2 = append(pchannels2, fmt.Sprintf("by-dev-rootcoord-dml_%d", idx)) + } + + ctx := context.Background() + err := streaming.WAL().Replicate().UpdateReplicateConfiguration(ctx, &commonpb.ReplicateConfiguration{ + Clusters: []*commonpb.MilvusCluster{ + { + ClusterId: "primary", + ConnectionParam: &commonpb.ConnectionParam{ + Uri: "localhost:19530", + Token: "test-token", + }, + Pchannels: pchannels1, + }, + { + ClusterId: "by-dev", + ConnectionParam: &commonpb.ConnectionParam{ + Uri: "localhost:19531", + Token: "test-token", + }, + Pchannels: pchannels2, + }, + }, + CrossClusterTopology: []*commonpb.CrossClusterTopology{ + { + SourceClusterId: "by-dev", + TargetClusterId: "primary", + }, + }, + }) + if err != nil { + panic(err) + } + cfg, err := streaming.WAL().Replicate().GetReplicateConfiguration(ctx) + if err != nil { + panic(err) + } + t.Logf("cfg: %+v\n", cfg) +} + func TestStreamingBroadcast(t *testing.T) { t.Skip("cat not running without streaming service at background") streamingutil.SetStreamingServiceEnabled() diff --git a/internal/distributed/streaming/test_streaming.go b/internal/distributed/streaming/test_streaming.go index 56ea5aaaa1..892dad925a 100644 --- a/internal/distributed/streaming/test_streaming.go +++ b/internal/distributed/streaming/test_streaming.go @@ -24,12 +24,15 @@ import ( "github.com/cockroachdb/errors" "google.golang.org/protobuf/types/known/anypb" + "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" + "github.com/milvus-io/milvus/internal/streamingnode/server/wal" kvfactory "github.com/milvus-io/milvus/internal/util/dependency/kv" "github.com/milvus-io/milvus/pkg/v2/proto/messagespb" "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" "github.com/milvus-io/milvus/pkg/v2/streaming/util/types" "github.com/milvus-io/milvus/pkg/v2/streaming/walimpls/impls/rmq" "github.com/milvus-io/milvus/pkg/v2/util/funcutil" + "github.com/milvus-io/milvus/pkg/v2/util/replicateutil" ) var expectErr = make(chan error, 10) @@ -52,6 +55,24 @@ func SetupNoopWALForTest() { singleton = &noopWALAccesser{} } +type noopReplicateService struct{} + +func (n *noopReplicateService) Append(ctx context.Context, msg message.ReplicateMutableMessage) (*types.AppendResult, error) { + return nil, nil +} + +func (n *noopReplicateService) UpdateReplicateConfiguration(ctx context.Context, config *commonpb.ReplicateConfiguration) error { + return nil +} + +func (n *noopReplicateService) GetReplicateConfiguration(ctx context.Context) (*replicateutil.ConfigHelper, error) { + return nil, nil +} + +func (n *noopReplicateService) GetReplicateCheckpoint(ctx context.Context, channelName string) (*wal.ReplicateCheckpoint, error) { + return nil, nil +} + type noopBalancer struct{} func (n *noopBalancer) ListStreamingNode(ctx context.Context) ([]types.StreamingNodeInfo, error) { @@ -139,6 +160,10 @@ func (n *noopTxn) Rollback(ctx context.Context) error { type noopWALAccesser struct{} +func (n *noopWALAccesser) Replicate() ReplicateService { + return &noopReplicateService{} +} + func (n *noopWALAccesser) ControlChannel() string { return funcutil.GetControlChannel("noop") } @@ -202,6 +227,18 @@ func (n *noopWALAccesser) AppendMessagesWithOption(ctx context.Context, opts App return AppendResponses{} } +func (n *noopWALAccesser) GetReplicateConfiguration(ctx context.Context) (*commonpb.ReplicateConfiguration, error) { + return nil, nil +} + +func (n *noopWALAccesser) GetReplicateCheckpoint(ctx context.Context, channelName string) (*commonpb.ReplicateCheckpoint, error) { + return nil, nil +} + +func (n *noopWALAccesser) UpdateReplicateConfiguration(ctx context.Context, config *commonpb.ReplicateConfiguration) error { + return nil +} + type noopScanner struct{} func (n *noopScanner) Done() <-chan struct{} { diff --git a/internal/distributed/streaming/wal.go b/internal/distributed/streaming/wal.go index 81c2980afa..6e38c4d687 100644 --- a/internal/distributed/streaming/wal.go +++ b/internal/distributed/streaming/wal.go @@ -12,12 +12,12 @@ import ( "github.com/milvus-io/milvus/internal/streamingcoord/client" "github.com/milvus-io/milvus/internal/streamingnode/client/handler" "github.com/milvus-io/milvus/internal/util/streamingutil/status" - "github.com/milvus-io/milvus/internal/util/streamingutil/util" "github.com/milvus-io/milvus/pkg/v2/log" "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" "github.com/milvus-io/milvus/pkg/v2/streaming/util/types" "github.com/milvus-io/milvus/pkg/v2/util/conc" "github.com/milvus-io/milvus/pkg/v2/util/funcutil" + "github.com/milvus-io/milvus/pkg/v2/util/paramtable" "github.com/milvus-io/milvus/pkg/v2/util/typeutil" ) @@ -31,6 +31,7 @@ func newWALAccesser(c *clientv3.Client) *walAccesserImpl { handlerClient := handler.NewHandlerClient(streamingCoordClient.Assignment()) w := &walAccesserImpl{ lifetime: typeutil.NewLifetime(), + clusterID: paramtable.Get().CommonCfg.ClusterPrefix.GetValue(), streamingCoordClient: streamingCoordClient, handlerClient: handlerClient, producerMutex: sync.Mutex{}, @@ -47,7 +48,8 @@ func newWALAccesser(c *clientv3.Client) *walAccesserImpl { // walAccesserImpl is the implementation of WALAccesser. type walAccesserImpl struct { log.Binder - lifetime *typeutil.Lifetime + lifetime *typeutil.Lifetime + clusterID string // All services streamingCoordClient client.Client @@ -59,12 +61,12 @@ type walAccesserImpl struct { dispatchExecutionPool *conc.Pool[struct{}] } -func (w *walAccesserImpl) Balancer() Balancer { - return balancerImpl{w} +func (w *walAccesserImpl) Replicate() ReplicateService { + return replicateService{w} } -func (w *walAccesserImpl) WALName() string { - return util.MustSelectWALName() +func (w *walAccesserImpl) Balancer() Balancer { + return balancerImpl{w} } func (w *walAccesserImpl) Local() Local { diff --git a/internal/metastore/catalog.go b/internal/metastore/catalog.go index 7d490639a4..157980cccf 100644 --- a/internal/metastore/catalog.go +++ b/internal/metastore/catalog.go @@ -207,8 +207,23 @@ type QueryCoordCatalog interface { GetCollectionTargets(ctx context.Context) (map[int64]*querypb.CollectionTarget, error) } +// ReplicationCatalog is the interface for replication catalog +// it's used by CDC component. +type ReplicationCatalog interface { + // RemoveReplicatePChannel removes the replicate pchannel from metastore. + // Remove the task of CDC replication task of current cluster, should be called when a CDC replication task is finished. + RemoveReplicatePChannel(ctx context.Context, sourceChannelName, targetChannelName string) error + + // ListReplicatePChannels lists all replicate pchannels from metastore. + // every ReplicatePChannelMeta is a task of CDC replication task of current cluster which is a source cluster in replication topology. + // the task is written by streaming coord, SaveReplicateConfiguration operation. + ListReplicatePChannels(ctx context.Context) ([]*streamingpb.ReplicatePChannelMeta, error) +} + // StreamingCoordCataLog is the interface for streamingcoord catalog type StreamingCoordCataLog interface { + ReplicationCatalog + // GetCChannel get the control channel from metastore. GetCChannel(ctx context.Context) (*streamingpb.CChannelMeta, error) @@ -237,6 +252,12 @@ type StreamingCoordCataLog interface { // Make the task recoverable after restart. // When broadcast task is done, it will be removed from metastore. SaveBroadcastTask(ctx context.Context, broadcastID uint64, task *streamingpb.BroadcastTask) error + + // SaveReplicateConfiguration saves the replicate configuration to metastore. + SaveReplicateConfiguration(ctx context.Context, config *streamingpb.ReplicateConfigurationMeta, replicatingTasks []*streamingpb.ReplicatePChannelMeta) error + + // GetReplicateConfiguration gets the replicate configuration from metastore. + GetReplicateConfiguration(ctx context.Context) (*streamingpb.ReplicateConfigurationMeta, error) } // StreamingNodeCataLog is the interface for streamingnode catalog diff --git a/internal/metastore/kv/streamingcoord/constant.go b/internal/metastore/kv/streamingcoord/constant.go index 5ec739d4c2..6dc83af63c 100644 --- a/internal/metastore/kv/streamingcoord/constant.go +++ b/internal/metastore/kv/streamingcoord/constant.go @@ -6,4 +6,8 @@ const ( BroadcastTaskPrefix = MetaPrefix + "broadcast-task/" VersionPrefix = MetaPrefix + "version/" CChannelMetaPrefix = MetaPrefix + "cchannel/" + + // Replicate + ReplicatePChannelMetaPrefix = MetaPrefix + "replicating-pchannel/" + ReplicateConfigurationKey = MetaPrefix + "replicate-configuration" ) diff --git a/internal/metastore/kv/streamingcoord/kv_catalog.go b/internal/metastore/kv/streamingcoord/kv_catalog.go index 2ec48d35db..ac409a64d6 100644 --- a/internal/metastore/kv/streamingcoord/kv_catalog.go +++ b/internal/metastore/kv/streamingcoord/kv_catalog.go @@ -2,6 +2,7 @@ package streamingcoord import ( "context" + "fmt" "strconv" "github.com/cockroachdb/errors" @@ -26,12 +27,25 @@ import ( // // ├── pchannel-1 // └── pchannel-2 +// +// └── replicate-configuration +// └── replicating-pchannel +// │   ├── cluster-1-pchannel-1 +// │   └── cluster-1-pchannel-2 +// │   ├── cluster-2-pchannel-1 +// │   └── cluster-2-pchannel-2 func NewCataLog(metaKV kv.MetaKv) metastore.StreamingCoordCataLog { return &catalog{ metaKV: metaKV, } } +func NewReplicationCatalog(metaKV kv.MetaKv) metastore.ReplicationCatalog { + return &catalog{ + metaKV: metaKV, + } +} + // catalog is a kv based catalog. type catalog struct { metaKV kv.MetaKv @@ -163,3 +177,67 @@ func buildPChannelInfoPath(name string) string { func buildBroadcastTaskPath(id uint64) string { return BroadcastTaskPrefix + strconv.FormatUint(id, 10) } + +func (c *catalog) SaveReplicateConfiguration(ctx context.Context, config *streamingpb.ReplicateConfigurationMeta, replicatingTasks []*streamingpb.ReplicatePChannelMeta) error { + v, err := proto.Marshal(config) + if err != nil { + return errors.Wrapf(err, "marshal replicate configuration failed") + } + + kvs := make(map[string]string, len(replicatingTasks)+1) + kvs[ReplicateConfigurationKey] = string(v) + + for _, task := range replicatingTasks { + key := buildReplicatePChannelPath(task.GetTargetCluster().GetClusterId(), task.GetSourceChannelName()) + v, err := proto.Marshal(task) + if err != nil { + return errors.Wrapf(err, "marshal replicate pchannel meta failed") + } + kvs[key] = string(v) + } + return etcd.SaveByBatchWithLimit(kvs, util.MaxEtcdTxnNum, func(partialKvs map[string]string) error { + return c.metaKV.MultiSave(ctx, partialKvs) + }) +} + +func (c *catalog) GetReplicateConfiguration(ctx context.Context) (*streamingpb.ReplicateConfigurationMeta, error) { + key := ReplicateConfigurationKey + value, err := c.metaKV.Load(ctx, key) + if err != nil { + if errors.Is(err, merr.ErrIoKeyNotFound) { + return nil, nil + } + return nil, err + } + config := &streamingpb.ReplicateConfigurationMeta{} + if err = proto.Unmarshal([]byte(value), config); err != nil { + return nil, errors.Wrapf(err, "unmarshal replicate configuration failed") + } + return config, nil +} + +func (c *catalog) RemoveReplicatePChannel(ctx context.Context, targetClusterID, sourceChannelName string) error { + key := buildReplicatePChannelPath(targetClusterID, sourceChannelName) + return c.metaKV.Remove(ctx, key) +} + +func (c *catalog) ListReplicatePChannels(ctx context.Context) ([]*streamingpb.ReplicatePChannelMeta, error) { + keys, values, err := c.metaKV.LoadWithPrefix(ctx, ReplicatePChannelMetaPrefix) + if err != nil { + return nil, err + } + infos := make([]*streamingpb.ReplicatePChannelMeta, 0, len(values)) + for k, value := range values { + info := &streamingpb.ReplicatePChannelMeta{} + err = proto.Unmarshal([]byte(value), info) + if err != nil { + return nil, errors.Wrapf(err, "unmarshal replicate pchannel meta %s failed", keys[k]) + } + infos = append(infos, info) + } + return infos, nil +} + +func buildReplicatePChannelPath(targetClusterID, sourceChannelName string) string { + return fmt.Sprintf("%s%s-%s", ReplicatePChannelMetaPrefix, targetClusterID, sourceChannelName) +} diff --git a/internal/metastore/kv/streamingcoord/kv_catalog_test.go b/internal/metastore/kv/streamingcoord/kv_catalog_test.go index f797bf638f..c11771db2d 100644 --- a/internal/metastore/kv/streamingcoord/kv_catalog_test.go +++ b/internal/metastore/kv/streamingcoord/kv_catalog_test.go @@ -2,6 +2,7 @@ package streamingcoord import ( "context" + "sort" "strings" "testing" @@ -9,6 +10,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" + "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" "github.com/milvus-io/milvus/pkg/v2/mocks/mock_kv" "github.com/milvus-io/milvus/pkg/v2/proto/streamingpb" ) @@ -139,3 +141,114 @@ func TestCatalog(t *testing.T) { err = catalog.SaveBroadcastTask(context.Background(), 1, &streamingpb.BroadcastTask{}) assert.Error(t, err) } + +func TestCatalog_ReplicationCatalog(t *testing.T) { + kv := mock_kv.NewMockMetaKv(t) + kvStorage := make(map[string]string) + kv.EXPECT().Load(mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, s string) (string, error) { + return kvStorage[s], nil + }) + kv.EXPECT().LoadWithPrefix(mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, s string) ([]string, []string, error) { + keys := make([]string, 0, len(kvStorage)) + vals := make([]string, 0, len(kvStorage)) + for k, v := range kvStorage { + if strings.HasPrefix(k, s) { + keys = append(keys, k) + vals = append(vals, v) + } + } + return keys, vals, nil + }) + kv.EXPECT().MultiSave(mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, kvs map[string]string) error { + for k, v := range kvs { + kvStorage[k] = v + } + return nil + }) + kv.EXPECT().Remove(mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, key string) error { + delete(kvStorage, key) + return nil + }) + + catalog := NewCataLog(kv) + + // ReplicateConfiguration test + config := &commonpb.ReplicateConfiguration{ + Clusters: []*commonpb.MilvusCluster{ + { + ClusterId: "source-cluster", + Pchannels: []string{"source-channel-1", "source-channel-2"}, + }, + { + ClusterId: "target-cluster-a", + Pchannels: []string{"target-channel-a-1", "target-channel-a-2"}, + }, + { + ClusterId: "target-cluster-b", + Pchannels: []string{"target-channel-b-1", "target-channel-b-2"}, + }, + }, + CrossClusterTopology: []*commonpb.CrossClusterTopology{ + { + SourceClusterId: "source-cluster", + TargetClusterId: "target-cluster-a", + }, + { + SourceClusterId: "source-cluster", + TargetClusterId: "target-cluster-b", + }, + }, + } + err := catalog.SaveReplicateConfiguration(context.Background(), &streamingpb.ReplicateConfigurationMeta{ReplicateConfiguration: config}, nil) + assert.NoError(t, err) + + cfg, err := catalog.GetReplicateConfiguration(context.Background()) + assert.NoError(t, err) + assert.Equal(t, cfg.ReplicateConfiguration.GetClusters()[0].GetClusterId(), "source-cluster") + assert.Equal(t, cfg.ReplicateConfiguration.GetClusters()[1].GetClusterId(), "target-cluster-a") + assert.Equal(t, cfg.ReplicateConfiguration.GetClusters()[2].GetClusterId(), "target-cluster-b") + assert.Equal(t, cfg.ReplicateConfiguration.GetCrossClusterTopology()[0].GetSourceClusterId(), "source-cluster") + assert.Equal(t, cfg.ReplicateConfiguration.GetCrossClusterTopology()[0].GetTargetClusterId(), "target-cluster-a") + assert.Equal(t, cfg.ReplicateConfiguration.GetCrossClusterTopology()[1].GetSourceClusterId(), "source-cluster") + assert.Equal(t, cfg.ReplicateConfiguration.GetCrossClusterTopology()[1].GetTargetClusterId(), "target-cluster-b") + + // ReplicatePChannel test + err = catalog.SaveReplicateConfiguration(context.Background(), + &streamingpb.ReplicateConfigurationMeta{ReplicateConfiguration: config}, + []*streamingpb.ReplicatePChannelMeta{ + { + SourceChannelName: "source-channel-1", + TargetChannelName: "target-channel-1", + TargetCluster: &commonpb.MilvusCluster{ClusterId: "target-cluster"}, + }, + { + SourceChannelName: "source-channel-2", + TargetChannelName: "target-channel-2", + TargetCluster: &commonpb.MilvusCluster{ClusterId: "target-cluster"}, + }, + }) + assert.NoError(t, err) + + infos, err := catalog.ListReplicatePChannels(context.Background()) + assert.NoError(t, err) + assert.Len(t, infos, 2) + sort.Slice(infos, func(i, j int) bool { + return infos[i].GetTargetChannelName() < infos[j].GetTargetChannelName() + }) + assert.Equal(t, infos[0].GetSourceChannelName(), "source-channel-1") + assert.Equal(t, infos[0].GetTargetChannelName(), "target-channel-1") + assert.Equal(t, infos[0].GetTargetCluster().GetClusterId(), "target-cluster") + assert.Equal(t, infos[1].GetSourceChannelName(), "source-channel-2") + assert.Equal(t, infos[1].GetTargetChannelName(), "target-channel-2") + assert.Equal(t, infos[1].GetTargetCluster().GetClusterId(), "target-cluster") + + err = catalog.RemoveReplicatePChannel(context.Background(), "target-cluster", "source-channel-1") + assert.NoError(t, err) + + infos, err = catalog.ListReplicatePChannels(context.Background()) + assert.NoError(t, err) + assert.Len(t, infos, 1) + assert.Equal(t, infos[0].GetSourceChannelName(), "source-channel-2") + assert.Equal(t, infos[0].GetTargetChannelName(), "target-channel-2") + assert.Equal(t, infos[0].GetTargetCluster().GetClusterId(), "target-cluster") +} diff --git a/internal/metastore/mocks/mock_rootcoord_catalog.go b/internal/metastore/mocks/mock_rootcoord_catalog.go index 998c6f28ea..3cbcfea32f 100644 --- a/internal/metastore/mocks/mock_rootcoord_catalog.go +++ b/internal/metastore/mocks/mock_rootcoord_catalog.go @@ -1767,64 +1767,6 @@ func (_c *RootCoordCatalog_ListDatabases_Call) RunAndReturn(run func(context.Con return _c } -// ListFileResource provides a mock function with given fields: ctx -func (_m *RootCoordCatalog) ListFileResource(ctx context.Context) ([]*model.FileResource, error) { - ret := _m.Called(ctx) - - if len(ret) == 0 { - panic("no return value specified for ListFileResource") - } - - var r0 []*model.FileResource - var r1 error - if rf, ok := ret.Get(0).(func(context.Context) ([]*model.FileResource, error)); ok { - return rf(ctx) - } - if rf, ok := ret.Get(0).(func(context.Context) []*model.FileResource); ok { - r0 = rf(ctx) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]*model.FileResource) - } - } - - if rf, ok := ret.Get(1).(func(context.Context) error); ok { - r1 = rf(ctx) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// RootCoordCatalog_ListFileResource_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListFileResource' -type RootCoordCatalog_ListFileResource_Call struct { - *mock.Call -} - -// ListFileResource is a helper method to define mock.On call -// - ctx context.Context -func (_e *RootCoordCatalog_Expecter) ListFileResource(ctx interface{}) *RootCoordCatalog_ListFileResource_Call { - return &RootCoordCatalog_ListFileResource_Call{Call: _e.mock.On("ListFileResource", ctx)} -} - -func (_c *RootCoordCatalog_ListFileResource_Call) Run(run func(ctx context.Context)) *RootCoordCatalog_ListFileResource_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context)) - }) - return _c -} - -func (_c *RootCoordCatalog_ListFileResource_Call) Return(_a0 []*model.FileResource, _a1 error) *RootCoordCatalog_ListFileResource_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *RootCoordCatalog_ListFileResource_Call) RunAndReturn(run func(context.Context) ([]*model.FileResource, error)) *RootCoordCatalog_ListFileResource_Call { - _c.Call.Return(run) - return _c -} - // ListGrant provides a mock function with given fields: ctx, tenant, entity func (_m *RootCoordCatalog) ListGrant(ctx context.Context, tenant string, entity *milvuspb.GrantEntity) ([]*milvuspb.GrantEntity, error) { ret := _m.Called(ctx, tenant, entity) @@ -2183,53 +2125,6 @@ func (_c *RootCoordCatalog_ListUserRole_Call) RunAndReturn(run func(context.Cont return _c } -// RemoveFileResource provides a mock function with given fields: ctx, resourceID -func (_m *RootCoordCatalog) RemoveFileResource(ctx context.Context, resourceID int64) error { - ret := _m.Called(ctx, resourceID) - - if len(ret) == 0 { - panic("no return value specified for RemoveFileResource") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, int64) error); ok { - r0 = rf(ctx, resourceID) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// RootCoordCatalog_RemoveFileResource_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveFileResource' -type RootCoordCatalog_RemoveFileResource_Call struct { - *mock.Call -} - -// RemoveFileResource is a helper method to define mock.On call -// - ctx context.Context -// - resourceID int64 -func (_e *RootCoordCatalog_Expecter) RemoveFileResource(ctx interface{}, resourceID interface{}) *RootCoordCatalog_RemoveFileResource_Call { - return &RootCoordCatalog_RemoveFileResource_Call{Call: _e.mock.On("RemoveFileResource", ctx, resourceID)} -} - -func (_c *RootCoordCatalog_RemoveFileResource_Call) Run(run func(ctx context.Context, resourceID int64)) *RootCoordCatalog_RemoveFileResource_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(int64)) - }) - return _c -} - -func (_c *RootCoordCatalog_RemoveFileResource_Call) Return(_a0 error) *RootCoordCatalog_RemoveFileResource_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *RootCoordCatalog_RemoveFileResource_Call) RunAndReturn(run func(context.Context, int64) error) *RootCoordCatalog_RemoveFileResource_Call { - _c.Call.Return(run) - return _c -} - // RestoreRBAC provides a mock function with given fields: ctx, tenant, meta func (_m *RootCoordCatalog) RestoreRBAC(ctx context.Context, tenant string, meta *milvuspb.RBACMeta) error { ret := _m.Called(ctx, tenant, meta) @@ -2278,53 +2173,6 @@ func (_c *RootCoordCatalog_RestoreRBAC_Call) RunAndReturn(run func(context.Conte return _c } -// SaveFileResource provides a mock function with given fields: ctx, resource -func (_m *RootCoordCatalog) SaveFileResource(ctx context.Context, resource *model.FileResource) error { - ret := _m.Called(ctx, resource) - - if len(ret) == 0 { - panic("no return value specified for SaveFileResource") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, *model.FileResource) error); ok { - r0 = rf(ctx, resource) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// RootCoordCatalog_SaveFileResource_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SaveFileResource' -type RootCoordCatalog_SaveFileResource_Call struct { - *mock.Call -} - -// SaveFileResource is a helper method to define mock.On call -// - ctx context.Context -// - resource *model.FileResource -func (_e *RootCoordCatalog_Expecter) SaveFileResource(ctx interface{}, resource interface{}) *RootCoordCatalog_SaveFileResource_Call { - return &RootCoordCatalog_SaveFileResource_Call{Call: _e.mock.On("SaveFileResource", ctx, resource)} -} - -func (_c *RootCoordCatalog_SaveFileResource_Call) Run(run func(ctx context.Context, resource *model.FileResource)) *RootCoordCatalog_SaveFileResource_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(*model.FileResource)) - }) - return _c -} - -func (_c *RootCoordCatalog_SaveFileResource_Call) Return(_a0 error) *RootCoordCatalog_SaveFileResource_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *RootCoordCatalog_SaveFileResource_Call) RunAndReturn(run func(context.Context, *model.FileResource) error) *RootCoordCatalog_SaveFileResource_Call { - _c.Call.Return(run) - return _c -} - // SavePrivilegeGroup provides a mock function with given fields: ctx, data func (_m *RootCoordCatalog) SavePrivilegeGroup(ctx context.Context, data *milvuspb.PrivilegeGroupInfo) error { ret := _m.Called(ctx, data) diff --git a/internal/mocks/distributed/mock_streaming/mock_ReplicateService.go b/internal/mocks/distributed/mock_streaming/mock_ReplicateService.go new file mode 100644 index 0000000000..5b1bda8597 --- /dev/null +++ b/internal/mocks/distributed/mock_streaming/mock_ReplicateService.go @@ -0,0 +1,269 @@ +// Code generated by mockery v2.53.3. DO NOT EDIT. + +package mock_streaming + +import ( + context "context" + + commonpb "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" + + message "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" + + mock "github.com/stretchr/testify/mock" + + replicateutil "github.com/milvus-io/milvus/pkg/v2/util/replicateutil" + + types "github.com/milvus-io/milvus/pkg/v2/streaming/util/types" + + wal "github.com/milvus-io/milvus/internal/streamingnode/server/wal" +) + +// MockReplicateService is an autogenerated mock type for the ReplicateService type +type MockReplicateService struct { + mock.Mock +} + +type MockReplicateService_Expecter struct { + mock *mock.Mock +} + +func (_m *MockReplicateService) EXPECT() *MockReplicateService_Expecter { + return &MockReplicateService_Expecter{mock: &_m.Mock} +} + +// Append provides a mock function with given fields: ctx, msg +func (_m *MockReplicateService) Append(ctx context.Context, msg message.ReplicateMutableMessage) (*types.AppendResult, error) { + ret := _m.Called(ctx, msg) + + if len(ret) == 0 { + panic("no return value specified for Append") + } + + var r0 *types.AppendResult + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, message.ReplicateMutableMessage) (*types.AppendResult, error)); ok { + return rf(ctx, msg) + } + if rf, ok := ret.Get(0).(func(context.Context, message.ReplicateMutableMessage) *types.AppendResult); ok { + r0 = rf(ctx, msg) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.AppendResult) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, message.ReplicateMutableMessage) error); ok { + r1 = rf(ctx, msg) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockReplicateService_Append_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Append' +type MockReplicateService_Append_Call struct { + *mock.Call +} + +// Append is a helper method to define mock.On call +// - ctx context.Context +// - msg message.ReplicateMutableMessage +func (_e *MockReplicateService_Expecter) Append(ctx interface{}, msg interface{}) *MockReplicateService_Append_Call { + return &MockReplicateService_Append_Call{Call: _e.mock.On("Append", ctx, msg)} +} + +func (_c *MockReplicateService_Append_Call) Run(run func(ctx context.Context, msg message.ReplicateMutableMessage)) *MockReplicateService_Append_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(message.ReplicateMutableMessage)) + }) + return _c +} + +func (_c *MockReplicateService_Append_Call) Return(_a0 *types.AppendResult, _a1 error) *MockReplicateService_Append_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockReplicateService_Append_Call) RunAndReturn(run func(context.Context, message.ReplicateMutableMessage) (*types.AppendResult, error)) *MockReplicateService_Append_Call { + _c.Call.Return(run) + return _c +} + +// GetReplicateCheckpoint provides a mock function with given fields: ctx, channelName +func (_m *MockReplicateService) GetReplicateCheckpoint(ctx context.Context, channelName string) (*wal.ReplicateCheckpoint, error) { + ret := _m.Called(ctx, channelName) + + if len(ret) == 0 { + panic("no return value specified for GetReplicateCheckpoint") + } + + var r0 *wal.ReplicateCheckpoint + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) (*wal.ReplicateCheckpoint, error)); ok { + return rf(ctx, channelName) + } + if rf, ok := ret.Get(0).(func(context.Context, string) *wal.ReplicateCheckpoint); ok { + r0 = rf(ctx, channelName) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*wal.ReplicateCheckpoint) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, channelName) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockReplicateService_GetReplicateCheckpoint_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetReplicateCheckpoint' +type MockReplicateService_GetReplicateCheckpoint_Call struct { + *mock.Call +} + +// GetReplicateCheckpoint is a helper method to define mock.On call +// - ctx context.Context +// - channelName string +func (_e *MockReplicateService_Expecter) GetReplicateCheckpoint(ctx interface{}, channelName interface{}) *MockReplicateService_GetReplicateCheckpoint_Call { + return &MockReplicateService_GetReplicateCheckpoint_Call{Call: _e.mock.On("GetReplicateCheckpoint", ctx, channelName)} +} + +func (_c *MockReplicateService_GetReplicateCheckpoint_Call) Run(run func(ctx context.Context, channelName string)) *MockReplicateService_GetReplicateCheckpoint_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string)) + }) + return _c +} + +func (_c *MockReplicateService_GetReplicateCheckpoint_Call) Return(_a0 *wal.ReplicateCheckpoint, _a1 error) *MockReplicateService_GetReplicateCheckpoint_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockReplicateService_GetReplicateCheckpoint_Call) RunAndReturn(run func(context.Context, string) (*wal.ReplicateCheckpoint, error)) *MockReplicateService_GetReplicateCheckpoint_Call { + _c.Call.Return(run) + return _c +} + +// GetReplicateConfiguration provides a mock function with given fields: ctx +func (_m *MockReplicateService) GetReplicateConfiguration(ctx context.Context) (*replicateutil.ConfigHelper, error) { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for GetReplicateConfiguration") + } + + var r0 *replicateutil.ConfigHelper + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (*replicateutil.ConfigHelper, error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) *replicateutil.ConfigHelper); ok { + r0 = rf(ctx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*replicateutil.ConfigHelper) + } + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockReplicateService_GetReplicateConfiguration_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetReplicateConfiguration' +type MockReplicateService_GetReplicateConfiguration_Call struct { + *mock.Call +} + +// GetReplicateConfiguration is a helper method to define mock.On call +// - ctx context.Context +func (_e *MockReplicateService_Expecter) GetReplicateConfiguration(ctx interface{}) *MockReplicateService_GetReplicateConfiguration_Call { + return &MockReplicateService_GetReplicateConfiguration_Call{Call: _e.mock.On("GetReplicateConfiguration", ctx)} +} + +func (_c *MockReplicateService_GetReplicateConfiguration_Call) Run(run func(ctx context.Context)) *MockReplicateService_GetReplicateConfiguration_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *MockReplicateService_GetReplicateConfiguration_Call) Return(_a0 *replicateutil.ConfigHelper, _a1 error) *MockReplicateService_GetReplicateConfiguration_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockReplicateService_GetReplicateConfiguration_Call) RunAndReturn(run func(context.Context) (*replicateutil.ConfigHelper, error)) *MockReplicateService_GetReplicateConfiguration_Call { + _c.Call.Return(run) + return _c +} + +// UpdateReplicateConfiguration provides a mock function with given fields: ctx, config +func (_m *MockReplicateService) UpdateReplicateConfiguration(ctx context.Context, config *commonpb.ReplicateConfiguration) error { + ret := _m.Called(ctx, config) + + if len(ret) == 0 { + panic("no return value specified for UpdateReplicateConfiguration") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *commonpb.ReplicateConfiguration) error); ok { + r0 = rf(ctx, config) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockReplicateService_UpdateReplicateConfiguration_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateReplicateConfiguration' +type MockReplicateService_UpdateReplicateConfiguration_Call struct { + *mock.Call +} + +// UpdateReplicateConfiguration is a helper method to define mock.On call +// - ctx context.Context +// - config *commonpb.ReplicateConfiguration +func (_e *MockReplicateService_Expecter) UpdateReplicateConfiguration(ctx interface{}, config interface{}) *MockReplicateService_UpdateReplicateConfiguration_Call { + return &MockReplicateService_UpdateReplicateConfiguration_Call{Call: _e.mock.On("UpdateReplicateConfiguration", ctx, config)} +} + +func (_c *MockReplicateService_UpdateReplicateConfiguration_Call) Run(run func(ctx context.Context, config *commonpb.ReplicateConfiguration)) *MockReplicateService_UpdateReplicateConfiguration_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*commonpb.ReplicateConfiguration)) + }) + return _c +} + +func (_c *MockReplicateService_UpdateReplicateConfiguration_Call) Return(_a0 error) *MockReplicateService_UpdateReplicateConfiguration_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockReplicateService_UpdateReplicateConfiguration_Call) RunAndReturn(run func(context.Context, *commonpb.ReplicateConfiguration) error) *MockReplicateService_UpdateReplicateConfiguration_Call { + _c.Call.Return(run) + return _c +} + +// NewMockReplicateService creates a new instance of MockReplicateService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockReplicateService(t interface { + mock.TestingT + Cleanup(func()) +}) *MockReplicateService { + mock := &MockReplicateService{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/internal/mocks/distributed/mock_streaming/mock_WALAccesser.go b/internal/mocks/distributed/mock_streaming/mock_WALAccesser.go index 5972889f1e..7f61e40848 100644 --- a/internal/mocks/distributed/mock_streaming/mock_WALAccesser.go +++ b/internal/mocks/distributed/mock_streaming/mock_WALAccesser.go @@ -458,6 +458,53 @@ func (_c *MockWALAccesser_Read_Call) RunAndReturn(run func(context.Context, stre return _c } +// Replicate provides a mock function with no fields +func (_m *MockWALAccesser) Replicate() streaming.ReplicateService { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Replicate") + } + + var r0 streaming.ReplicateService + if rf, ok := ret.Get(0).(func() streaming.ReplicateService); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(streaming.ReplicateService) + } + } + + return r0 +} + +// MockWALAccesser_Replicate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Replicate' +type MockWALAccesser_Replicate_Call struct { + *mock.Call +} + +// Replicate is a helper method to define mock.On call +func (_e *MockWALAccesser_Expecter) Replicate() *MockWALAccesser_Replicate_Call { + return &MockWALAccesser_Replicate_Call{Call: _e.mock.On("Replicate")} +} + +func (_c *MockWALAccesser_Replicate_Call) Run(run func()) *MockWALAccesser_Replicate_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockWALAccesser_Replicate_Call) Return(_a0 streaming.ReplicateService) *MockWALAccesser_Replicate_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockWALAccesser_Replicate_Call) RunAndReturn(run func() streaming.ReplicateService) *MockWALAccesser_Replicate_Call { + _c.Call.Return(run) + return _c +} + // Txn provides a mock function with given fields: ctx, opts func (_m *MockWALAccesser) Txn(ctx context.Context, opts streaming.TxnOption) (streaming.Txn, error) { ret := _m.Called(ctx, opts) @@ -517,51 +564,6 @@ func (_c *MockWALAccesser_Txn_Call) RunAndReturn(run func(context.Context, strea return _c } -// WALName provides a mock function with no fields -func (_m *MockWALAccesser) WALName() string { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for WALName") - } - - var r0 string - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - return r0 -} - -// MockWALAccesser_WALName_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WALName' -type MockWALAccesser_WALName_Call struct { - *mock.Call -} - -// WALName is a helper method to define mock.On call -func (_e *MockWALAccesser_Expecter) WALName() *MockWALAccesser_WALName_Call { - return &MockWALAccesser_WALName_Call{Call: _e.mock.On("WALName")} -} - -func (_c *MockWALAccesser_WALName_Call) Run(run func()) *MockWALAccesser_WALName_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockWALAccesser_WALName_Call) Return(_a0 string) *MockWALAccesser_WALName_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockWALAccesser_WALName_Call) RunAndReturn(run func() string) *MockWALAccesser_WALName_Call { - _c.Call.Return(run) - return _c -} - // NewMockWALAccesser creates a new instance of MockWALAccesser. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewMockWALAccesser(t interface { diff --git a/internal/mocks/mock_metastore/mock_ReplicationCatalog.go b/internal/mocks/mock_metastore/mock_ReplicationCatalog.go new file mode 100644 index 0000000000..b0740e5c64 --- /dev/null +++ b/internal/mocks/mock_metastore/mock_ReplicationCatalog.go @@ -0,0 +1,144 @@ +// Code generated by mockery v2.53.3. DO NOT EDIT. + +package mock_metastore + +import ( + context "context" + + mock "github.com/stretchr/testify/mock" + + streamingpb "github.com/milvus-io/milvus/pkg/v2/proto/streamingpb" +) + +// MockReplicationCatalog is an autogenerated mock type for the ReplicationCatalog type +type MockReplicationCatalog struct { + mock.Mock +} + +type MockReplicationCatalog_Expecter struct { + mock *mock.Mock +} + +func (_m *MockReplicationCatalog) EXPECT() *MockReplicationCatalog_Expecter { + return &MockReplicationCatalog_Expecter{mock: &_m.Mock} +} + +// ListReplicatePChannels provides a mock function with given fields: ctx +func (_m *MockReplicationCatalog) ListReplicatePChannels(ctx context.Context) ([]*streamingpb.ReplicatePChannelMeta, error) { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for ListReplicatePChannels") + } + + var r0 []*streamingpb.ReplicatePChannelMeta + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) ([]*streamingpb.ReplicatePChannelMeta, error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) []*streamingpb.ReplicatePChannelMeta); ok { + r0 = rf(ctx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*streamingpb.ReplicatePChannelMeta) + } + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockReplicationCatalog_ListReplicatePChannels_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListReplicatePChannels' +type MockReplicationCatalog_ListReplicatePChannels_Call struct { + *mock.Call +} + +// ListReplicatePChannels is a helper method to define mock.On call +// - ctx context.Context +func (_e *MockReplicationCatalog_Expecter) ListReplicatePChannels(ctx interface{}) *MockReplicationCatalog_ListReplicatePChannels_Call { + return &MockReplicationCatalog_ListReplicatePChannels_Call{Call: _e.mock.On("ListReplicatePChannels", ctx)} +} + +func (_c *MockReplicationCatalog_ListReplicatePChannels_Call) Run(run func(ctx context.Context)) *MockReplicationCatalog_ListReplicatePChannels_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *MockReplicationCatalog_ListReplicatePChannels_Call) Return(_a0 []*streamingpb.ReplicatePChannelMeta, _a1 error) *MockReplicationCatalog_ListReplicatePChannels_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockReplicationCatalog_ListReplicatePChannels_Call) RunAndReturn(run func(context.Context) ([]*streamingpb.ReplicatePChannelMeta, error)) *MockReplicationCatalog_ListReplicatePChannels_Call { + _c.Call.Return(run) + return _c +} + +// RemoveReplicatePChannel provides a mock function with given fields: ctx, sourceChannelName, targetChannelName +func (_m *MockReplicationCatalog) RemoveReplicatePChannel(ctx context.Context, sourceChannelName string, targetChannelName string) error { + ret := _m.Called(ctx, sourceChannelName, targetChannelName) + + if len(ret) == 0 { + panic("no return value specified for RemoveReplicatePChannel") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok { + r0 = rf(ctx, sourceChannelName, targetChannelName) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockReplicationCatalog_RemoveReplicatePChannel_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveReplicatePChannel' +type MockReplicationCatalog_RemoveReplicatePChannel_Call struct { + *mock.Call +} + +// RemoveReplicatePChannel is a helper method to define mock.On call +// - ctx context.Context +// - sourceChannelName string +// - targetChannelName string +func (_e *MockReplicationCatalog_Expecter) RemoveReplicatePChannel(ctx interface{}, sourceChannelName interface{}, targetChannelName interface{}) *MockReplicationCatalog_RemoveReplicatePChannel_Call { + return &MockReplicationCatalog_RemoveReplicatePChannel_Call{Call: _e.mock.On("RemoveReplicatePChannel", ctx, sourceChannelName, targetChannelName)} +} + +func (_c *MockReplicationCatalog_RemoveReplicatePChannel_Call) Run(run func(ctx context.Context, sourceChannelName string, targetChannelName string)) *MockReplicationCatalog_RemoveReplicatePChannel_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string), args[2].(string)) + }) + return _c +} + +func (_c *MockReplicationCatalog_RemoveReplicatePChannel_Call) Return(_a0 error) *MockReplicationCatalog_RemoveReplicatePChannel_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockReplicationCatalog_RemoveReplicatePChannel_Call) RunAndReturn(run func(context.Context, string, string) error) *MockReplicationCatalog_RemoveReplicatePChannel_Call { + _c.Call.Return(run) + return _c +} + +// NewMockReplicationCatalog creates a new instance of MockReplicationCatalog. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockReplicationCatalog(t interface { + mock.TestingT + Cleanup(func()) +}) *MockReplicationCatalog { + mock := &MockReplicationCatalog{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/internal/mocks/mock_metastore/mock_StreamingCoordCataLog.go b/internal/mocks/mock_metastore/mock_StreamingCoordCataLog.go index e2ad681449..3ded0842a1 100644 --- a/internal/mocks/mock_metastore/mock_StreamingCoordCataLog.go +++ b/internal/mocks/mock_metastore/mock_StreamingCoordCataLog.go @@ -81,6 +81,64 @@ func (_c *MockStreamingCoordCataLog_GetCChannel_Call) RunAndReturn(run func(cont return _c } +// GetReplicateConfiguration provides a mock function with given fields: ctx +func (_m *MockStreamingCoordCataLog) GetReplicateConfiguration(ctx context.Context) (*streamingpb.ReplicateConfigurationMeta, error) { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for GetReplicateConfiguration") + } + + var r0 *streamingpb.ReplicateConfigurationMeta + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (*streamingpb.ReplicateConfigurationMeta, error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) *streamingpb.ReplicateConfigurationMeta); ok { + r0 = rf(ctx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*streamingpb.ReplicateConfigurationMeta) + } + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockStreamingCoordCataLog_GetReplicateConfiguration_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetReplicateConfiguration' +type MockStreamingCoordCataLog_GetReplicateConfiguration_Call struct { + *mock.Call +} + +// GetReplicateConfiguration is a helper method to define mock.On call +// - ctx context.Context +func (_e *MockStreamingCoordCataLog_Expecter) GetReplicateConfiguration(ctx interface{}) *MockStreamingCoordCataLog_GetReplicateConfiguration_Call { + return &MockStreamingCoordCataLog_GetReplicateConfiguration_Call{Call: _e.mock.On("GetReplicateConfiguration", ctx)} +} + +func (_c *MockStreamingCoordCataLog_GetReplicateConfiguration_Call) Run(run func(ctx context.Context)) *MockStreamingCoordCataLog_GetReplicateConfiguration_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *MockStreamingCoordCataLog_GetReplicateConfiguration_Call) Return(_a0 *streamingpb.ReplicateConfigurationMeta, _a1 error) *MockStreamingCoordCataLog_GetReplicateConfiguration_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockStreamingCoordCataLog_GetReplicateConfiguration_Call) RunAndReturn(run func(context.Context) (*streamingpb.ReplicateConfigurationMeta, error)) *MockStreamingCoordCataLog_GetReplicateConfiguration_Call { + _c.Call.Return(run) + return _c +} + // GetVersion provides a mock function with given fields: ctx func (_m *MockStreamingCoordCataLog) GetVersion(ctx context.Context) (*streamingpb.StreamingVersion, error) { ret := _m.Called(ctx) @@ -255,6 +313,112 @@ func (_c *MockStreamingCoordCataLog_ListPChannel_Call) RunAndReturn(run func(con return _c } +// ListReplicatePChannels provides a mock function with given fields: ctx +func (_m *MockStreamingCoordCataLog) ListReplicatePChannels(ctx context.Context) ([]*streamingpb.ReplicatePChannelMeta, error) { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for ListReplicatePChannels") + } + + var r0 []*streamingpb.ReplicatePChannelMeta + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) ([]*streamingpb.ReplicatePChannelMeta, error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) []*streamingpb.ReplicatePChannelMeta); ok { + r0 = rf(ctx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*streamingpb.ReplicatePChannelMeta) + } + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockStreamingCoordCataLog_ListReplicatePChannels_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListReplicatePChannels' +type MockStreamingCoordCataLog_ListReplicatePChannels_Call struct { + *mock.Call +} + +// ListReplicatePChannels is a helper method to define mock.On call +// - ctx context.Context +func (_e *MockStreamingCoordCataLog_Expecter) ListReplicatePChannels(ctx interface{}) *MockStreamingCoordCataLog_ListReplicatePChannels_Call { + return &MockStreamingCoordCataLog_ListReplicatePChannels_Call{Call: _e.mock.On("ListReplicatePChannels", ctx)} +} + +func (_c *MockStreamingCoordCataLog_ListReplicatePChannels_Call) Run(run func(ctx context.Context)) *MockStreamingCoordCataLog_ListReplicatePChannels_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *MockStreamingCoordCataLog_ListReplicatePChannels_Call) Return(_a0 []*streamingpb.ReplicatePChannelMeta, _a1 error) *MockStreamingCoordCataLog_ListReplicatePChannels_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockStreamingCoordCataLog_ListReplicatePChannels_Call) RunAndReturn(run func(context.Context) ([]*streamingpb.ReplicatePChannelMeta, error)) *MockStreamingCoordCataLog_ListReplicatePChannels_Call { + _c.Call.Return(run) + return _c +} + +// RemoveReplicatePChannel provides a mock function with given fields: ctx, sourceChannelName, targetChannelName +func (_m *MockStreamingCoordCataLog) RemoveReplicatePChannel(ctx context.Context, sourceChannelName string, targetChannelName string) error { + ret := _m.Called(ctx, sourceChannelName, targetChannelName) + + if len(ret) == 0 { + panic("no return value specified for RemoveReplicatePChannel") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok { + r0 = rf(ctx, sourceChannelName, targetChannelName) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockStreamingCoordCataLog_RemoveReplicatePChannel_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveReplicatePChannel' +type MockStreamingCoordCataLog_RemoveReplicatePChannel_Call struct { + *mock.Call +} + +// RemoveReplicatePChannel is a helper method to define mock.On call +// - ctx context.Context +// - sourceChannelName string +// - targetChannelName string +func (_e *MockStreamingCoordCataLog_Expecter) RemoveReplicatePChannel(ctx interface{}, sourceChannelName interface{}, targetChannelName interface{}) *MockStreamingCoordCataLog_RemoveReplicatePChannel_Call { + return &MockStreamingCoordCataLog_RemoveReplicatePChannel_Call{Call: _e.mock.On("RemoveReplicatePChannel", ctx, sourceChannelName, targetChannelName)} +} + +func (_c *MockStreamingCoordCataLog_RemoveReplicatePChannel_Call) Run(run func(ctx context.Context, sourceChannelName string, targetChannelName string)) *MockStreamingCoordCataLog_RemoveReplicatePChannel_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string), args[2].(string)) + }) + return _c +} + +func (_c *MockStreamingCoordCataLog_RemoveReplicatePChannel_Call) Return(_a0 error) *MockStreamingCoordCataLog_RemoveReplicatePChannel_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockStreamingCoordCataLog_RemoveReplicatePChannel_Call) RunAndReturn(run func(context.Context, string, string) error) *MockStreamingCoordCataLog_RemoveReplicatePChannel_Call { + _c.Call.Return(run) + return _c +} + // SaveBroadcastTask provides a mock function with given fields: ctx, broadcastID, task func (_m *MockStreamingCoordCataLog) SaveBroadcastTask(ctx context.Context, broadcastID uint64, task *streamingpb.BroadcastTask) error { ret := _m.Called(ctx, broadcastID, task) @@ -397,6 +561,54 @@ func (_c *MockStreamingCoordCataLog_SavePChannels_Call) RunAndReturn(run func(co return _c } +// SaveReplicateConfiguration provides a mock function with given fields: ctx, config, replicatingTasks +func (_m *MockStreamingCoordCataLog) SaveReplicateConfiguration(ctx context.Context, config *streamingpb.ReplicateConfigurationMeta, replicatingTasks []*streamingpb.ReplicatePChannelMeta) error { + ret := _m.Called(ctx, config, replicatingTasks) + + if len(ret) == 0 { + panic("no return value specified for SaveReplicateConfiguration") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *streamingpb.ReplicateConfigurationMeta, []*streamingpb.ReplicatePChannelMeta) error); ok { + r0 = rf(ctx, config, replicatingTasks) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockStreamingCoordCataLog_SaveReplicateConfiguration_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SaveReplicateConfiguration' +type MockStreamingCoordCataLog_SaveReplicateConfiguration_Call struct { + *mock.Call +} + +// SaveReplicateConfiguration is a helper method to define mock.On call +// - ctx context.Context +// - config *streamingpb.ReplicateConfigurationMeta +// - replicatingTasks []*streamingpb.ReplicatePChannelMeta +func (_e *MockStreamingCoordCataLog_Expecter) SaveReplicateConfiguration(ctx interface{}, config interface{}, replicatingTasks interface{}) *MockStreamingCoordCataLog_SaveReplicateConfiguration_Call { + return &MockStreamingCoordCataLog_SaveReplicateConfiguration_Call{Call: _e.mock.On("SaveReplicateConfiguration", ctx, config, replicatingTasks)} +} + +func (_c *MockStreamingCoordCataLog_SaveReplicateConfiguration_Call) Run(run func(ctx context.Context, config *streamingpb.ReplicateConfigurationMeta, replicatingTasks []*streamingpb.ReplicatePChannelMeta)) *MockStreamingCoordCataLog_SaveReplicateConfiguration_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*streamingpb.ReplicateConfigurationMeta), args[2].([]*streamingpb.ReplicatePChannelMeta)) + }) + return _c +} + +func (_c *MockStreamingCoordCataLog_SaveReplicateConfiguration_Call) Return(_a0 error) *MockStreamingCoordCataLog_SaveReplicateConfiguration_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockStreamingCoordCataLog_SaveReplicateConfiguration_Call) RunAndReturn(run func(context.Context, *streamingpb.ReplicateConfigurationMeta, []*streamingpb.ReplicatePChannelMeta) error) *MockStreamingCoordCataLog_SaveReplicateConfiguration_Call { + _c.Call.Return(run) + return _c +} + // SaveVersion provides a mock function with given fields: ctx, version func (_m *MockStreamingCoordCataLog) SaveVersion(ctx context.Context, version *streamingpb.StreamingVersion) error { ret := _m.Called(ctx, version) diff --git a/internal/mocks/streamingcoord/mock_client/mock_AssignmentService.go b/internal/mocks/streamingcoord/mock_client/mock_AssignmentService.go index 95b2f7589e..d5088dc481 100644 --- a/internal/mocks/streamingcoord/mock_client/mock_AssignmentService.go +++ b/internal/mocks/streamingcoord/mock_client/mock_AssignmentService.go @@ -5,8 +5,13 @@ package mock_client import ( context "context" - types "github.com/milvus-io/milvus/pkg/v2/streaming/util/types" + commonpb "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" + mock "github.com/stretchr/testify/mock" + + replicateutil "github.com/milvus-io/milvus/pkg/v2/util/replicateutil" + + types "github.com/milvus-io/milvus/pkg/v2/streaming/util/types" ) // MockAssignmentService is an autogenerated mock type for the AssignmentService type @@ -127,6 +132,64 @@ func (_c *MockAssignmentService_GetLatestAssignments_Call) RunAndReturn(run func return _c } +// GetReplicateConfiguration provides a mock function with given fields: ctx +func (_m *MockAssignmentService) GetReplicateConfiguration(ctx context.Context) (*replicateutil.ConfigHelper, error) { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for GetReplicateConfiguration") + } + + var r0 *replicateutil.ConfigHelper + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (*replicateutil.ConfigHelper, error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) *replicateutil.ConfigHelper); ok { + r0 = rf(ctx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*replicateutil.ConfigHelper) + } + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockAssignmentService_GetReplicateConfiguration_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetReplicateConfiguration' +type MockAssignmentService_GetReplicateConfiguration_Call struct { + *mock.Call +} + +// GetReplicateConfiguration is a helper method to define mock.On call +// - ctx context.Context +func (_e *MockAssignmentService_Expecter) GetReplicateConfiguration(ctx interface{}) *MockAssignmentService_GetReplicateConfiguration_Call { + return &MockAssignmentService_GetReplicateConfiguration_Call{Call: _e.mock.On("GetReplicateConfiguration", ctx)} +} + +func (_c *MockAssignmentService_GetReplicateConfiguration_Call) Run(run func(ctx context.Context)) *MockAssignmentService_GetReplicateConfiguration_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *MockAssignmentService_GetReplicateConfiguration_Call) Return(_a0 *replicateutil.ConfigHelper, _a1 error) *MockAssignmentService_GetReplicateConfiguration_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockAssignmentService_GetReplicateConfiguration_Call) RunAndReturn(run func(context.Context) (*replicateutil.ConfigHelper, error)) *MockAssignmentService_GetReplicateConfiguration_Call { + _c.Call.Return(run) + return _c +} + // ReportAssignmentError provides a mock function with given fields: ctx, pchannel, err func (_m *MockAssignmentService) ReportAssignmentError(ctx context.Context, pchannel types.PChannelInfo, err error) error { ret := _m.Called(ctx, pchannel, err) @@ -175,6 +238,53 @@ func (_c *MockAssignmentService_ReportAssignmentError_Call) RunAndReturn(run fun return _c } +// UpdateReplicateConfiguration provides a mock function with given fields: ctx, config +func (_m *MockAssignmentService) UpdateReplicateConfiguration(ctx context.Context, config *commonpb.ReplicateConfiguration) error { + ret := _m.Called(ctx, config) + + if len(ret) == 0 { + panic("no return value specified for UpdateReplicateConfiguration") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *commonpb.ReplicateConfiguration) error); ok { + r0 = rf(ctx, config) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockAssignmentService_UpdateReplicateConfiguration_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateReplicateConfiguration' +type MockAssignmentService_UpdateReplicateConfiguration_Call struct { + *mock.Call +} + +// UpdateReplicateConfiguration is a helper method to define mock.On call +// - ctx context.Context +// - config *commonpb.ReplicateConfiguration +func (_e *MockAssignmentService_Expecter) UpdateReplicateConfiguration(ctx interface{}, config interface{}) *MockAssignmentService_UpdateReplicateConfiguration_Call { + return &MockAssignmentService_UpdateReplicateConfiguration_Call{Call: _e.mock.On("UpdateReplicateConfiguration", ctx, config)} +} + +func (_c *MockAssignmentService_UpdateReplicateConfiguration_Call) Run(run func(ctx context.Context, config *commonpb.ReplicateConfiguration)) *MockAssignmentService_UpdateReplicateConfiguration_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*commonpb.ReplicateConfiguration)) + }) + return _c +} + +func (_c *MockAssignmentService_UpdateReplicateConfiguration_Call) Return(_a0 error) *MockAssignmentService_UpdateReplicateConfiguration_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockAssignmentService_UpdateReplicateConfiguration_Call) RunAndReturn(run func(context.Context, *commonpb.ReplicateConfiguration) error) *MockAssignmentService_UpdateReplicateConfiguration_Call { + _c.Call.Return(run) + return _c +} + // UpdateWALBalancePolicy provides a mock function with given fields: ctx, req func (_m *MockAssignmentService) UpdateWALBalancePolicy(ctx context.Context, req *types.UpdateWALBalancePolicyRequest) (*types.UpdateWALBalancePolicyResponse, error) { ret := _m.Called(ctx, req) diff --git a/internal/mocks/streamingcoord/server/mock_balancer/mock_Balancer.go b/internal/mocks/streamingcoord/server/mock_balancer/mock_Balancer.go index 5194470256..f9ba9067f6 100644 --- a/internal/mocks/streamingcoord/server/mock_balancer/mock_Balancer.go +++ b/internal/mocks/streamingcoord/server/mock_balancer/mock_Balancer.go @@ -7,6 +7,8 @@ import ( balancer "github.com/milvus-io/milvus/internal/streamingcoord/server/balancer" + message "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" + mock "github.com/stretchr/testify/mock" streamingpb "github.com/milvus-io/milvus/pkg/v2/proto/streamingpb" @@ -119,6 +121,63 @@ func (_c *MockBalancer_GetAllStreamingNodes_Call) RunAndReturn(run func(context. return _c } +// GetLatestChannelAssignment provides a mock function with no fields +func (_m *MockBalancer) GetLatestChannelAssignment() (*balancer.WatchChannelAssignmentsCallbackParam, error) { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for GetLatestChannelAssignment") + } + + var r0 *balancer.WatchChannelAssignmentsCallbackParam + var r1 error + if rf, ok := ret.Get(0).(func() (*balancer.WatchChannelAssignmentsCallbackParam, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() *balancer.WatchChannelAssignmentsCallbackParam); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*balancer.WatchChannelAssignmentsCallbackParam) + } + } + + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockBalancer_GetLatestChannelAssignment_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetLatestChannelAssignment' +type MockBalancer_GetLatestChannelAssignment_Call struct { + *mock.Call +} + +// GetLatestChannelAssignment is a helper method to define mock.On call +func (_e *MockBalancer_Expecter) GetLatestChannelAssignment() *MockBalancer_GetLatestChannelAssignment_Call { + return &MockBalancer_GetLatestChannelAssignment_Call{Call: _e.mock.On("GetLatestChannelAssignment")} +} + +func (_c *MockBalancer_GetLatestChannelAssignment_Call) Run(run func()) *MockBalancer_GetLatestChannelAssignment_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockBalancer_GetLatestChannelAssignment_Call) Return(_a0 *balancer.WatchChannelAssignmentsCallbackParam, _a1 error) *MockBalancer_GetLatestChannelAssignment_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockBalancer_GetLatestChannelAssignment_Call) RunAndReturn(run func() (*balancer.WatchChannelAssignmentsCallbackParam, error)) *MockBalancer_GetLatestChannelAssignment_Call { + _c.Call.Return(run) + return _c +} + // GetLatestWALLocated provides a mock function with given fields: ctx, pchannel func (_m *MockBalancer) GetLatestWALLocated(ctx context.Context, pchannel string) (int64, bool) { ret := _m.Called(ctx, pchannel) @@ -361,6 +420,67 @@ func (_c *MockBalancer_UpdateBalancePolicy_Call) RunAndReturn(run func(context.C return _c } +// UpdateReplicateConfiguration provides a mock function with given fields: ctx, msgs +func (_m *MockBalancer) UpdateReplicateConfiguration(ctx context.Context, msgs ...message.ImmutablePutReplicateConfigMessageV2) error { + _va := make([]interface{}, len(msgs)) + for _i := range msgs { + _va[_i] = msgs[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for UpdateReplicateConfiguration") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, ...message.ImmutablePutReplicateConfigMessageV2) error); ok { + r0 = rf(ctx, msgs...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockBalancer_UpdateReplicateConfiguration_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateReplicateConfiguration' +type MockBalancer_UpdateReplicateConfiguration_Call struct { + *mock.Call +} + +// UpdateReplicateConfiguration is a helper method to define mock.On call +// - ctx context.Context +// - msgs ...message.ImmutablePutReplicateConfigMessageV2 +func (_e *MockBalancer_Expecter) UpdateReplicateConfiguration(ctx interface{}, msgs ...interface{}) *MockBalancer_UpdateReplicateConfiguration_Call { + return &MockBalancer_UpdateReplicateConfiguration_Call{Call: _e.mock.On("UpdateReplicateConfiguration", + append([]interface{}{ctx}, msgs...)...)} +} + +func (_c *MockBalancer_UpdateReplicateConfiguration_Call) Run(run func(ctx context.Context, msgs ...message.ImmutablePutReplicateConfigMessageV2)) *MockBalancer_UpdateReplicateConfiguration_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]message.ImmutablePutReplicateConfigMessageV2, len(args)-1) + for i, a := range args[1:] { + if a != nil { + variadicArgs[i] = a.(message.ImmutablePutReplicateConfigMessageV2) + } + } + run(args[0].(context.Context), variadicArgs...) + }) + return _c +} + +func (_c *MockBalancer_UpdateReplicateConfiguration_Call) Return(_a0 error) *MockBalancer_UpdateReplicateConfiguration_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockBalancer_UpdateReplicateConfiguration_Call) RunAndReturn(run func(context.Context, ...message.ImmutablePutReplicateConfigMessageV2) error) *MockBalancer_UpdateReplicateConfiguration_Call { + _c.Call.Return(run) + return _c +} + // WatchChannelAssignments provides a mock function with given fields: ctx, cb func (_m *MockBalancer) WatchChannelAssignments(ctx context.Context, cb balancer.WatchChannelAssignmentsCallback) error { ret := _m.Called(ctx, cb) diff --git a/internal/mocks/streamingcoord/server/mock_broadcaster/mock_Broadcaster.go b/internal/mocks/streamingcoord/server/mock_broadcaster/mock_Broadcaster.go new file mode 100644 index 0000000000..ac5a2a186a --- /dev/null +++ b/internal/mocks/streamingcoord/server/mock_broadcaster/mock_Broadcaster.go @@ -0,0 +1,225 @@ +// Code generated by mockery v2.53.3. DO NOT EDIT. + +package mock_broadcaster + +import ( + context "context" + + message "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" + mock "github.com/stretchr/testify/mock" + + types "github.com/milvus-io/milvus/pkg/v2/streaming/util/types" +) + +// MockBroadcaster is an autogenerated mock type for the Broadcaster type +type MockBroadcaster struct { + mock.Mock +} + +type MockBroadcaster_Expecter struct { + mock *mock.Mock +} + +func (_m *MockBroadcaster) EXPECT() *MockBroadcaster_Expecter { + return &MockBroadcaster_Expecter{mock: &_m.Mock} +} + +// Ack provides a mock function with given fields: ctx, msg +func (_m *MockBroadcaster) Ack(ctx context.Context, msg message.ImmutableMessage) error { + ret := _m.Called(ctx, msg) + + if len(ret) == 0 { + panic("no return value specified for Ack") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, message.ImmutableMessage) error); ok { + r0 = rf(ctx, msg) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockBroadcaster_Ack_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Ack' +type MockBroadcaster_Ack_Call struct { + *mock.Call +} + +// Ack is a helper method to define mock.On call +// - ctx context.Context +// - msg message.ImmutableMessage +func (_e *MockBroadcaster_Expecter) Ack(ctx interface{}, msg interface{}) *MockBroadcaster_Ack_Call { + return &MockBroadcaster_Ack_Call{Call: _e.mock.On("Ack", ctx, msg)} +} + +func (_c *MockBroadcaster_Ack_Call) Run(run func(ctx context.Context, msg message.ImmutableMessage)) *MockBroadcaster_Ack_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(message.ImmutableMessage)) + }) + return _c +} + +func (_c *MockBroadcaster_Ack_Call) Return(_a0 error) *MockBroadcaster_Ack_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockBroadcaster_Ack_Call) RunAndReturn(run func(context.Context, message.ImmutableMessage) error) *MockBroadcaster_Ack_Call { + _c.Call.Return(run) + return _c +} + +// Broadcast provides a mock function with given fields: ctx, msg +func (_m *MockBroadcaster) Broadcast(ctx context.Context, msg message.BroadcastMutableMessage) (*types.BroadcastAppendResult, error) { + ret := _m.Called(ctx, msg) + + if len(ret) == 0 { + panic("no return value specified for Broadcast") + } + + var r0 *types.BroadcastAppendResult + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, message.BroadcastMutableMessage) (*types.BroadcastAppendResult, error)); ok { + return rf(ctx, msg) + } + if rf, ok := ret.Get(0).(func(context.Context, message.BroadcastMutableMessage) *types.BroadcastAppendResult); ok { + r0 = rf(ctx, msg) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.BroadcastAppendResult) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, message.BroadcastMutableMessage) error); ok { + r1 = rf(ctx, msg) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockBroadcaster_Broadcast_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Broadcast' +type MockBroadcaster_Broadcast_Call struct { + *mock.Call +} + +// Broadcast is a helper method to define mock.On call +// - ctx context.Context +// - msg message.BroadcastMutableMessage +func (_e *MockBroadcaster_Expecter) Broadcast(ctx interface{}, msg interface{}) *MockBroadcaster_Broadcast_Call { + return &MockBroadcaster_Broadcast_Call{Call: _e.mock.On("Broadcast", ctx, msg)} +} + +func (_c *MockBroadcaster_Broadcast_Call) Run(run func(ctx context.Context, msg message.BroadcastMutableMessage)) *MockBroadcaster_Broadcast_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(message.BroadcastMutableMessage)) + }) + return _c +} + +func (_c *MockBroadcaster_Broadcast_Call) Return(_a0 *types.BroadcastAppendResult, _a1 error) *MockBroadcaster_Broadcast_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockBroadcaster_Broadcast_Call) RunAndReturn(run func(context.Context, message.BroadcastMutableMessage) (*types.BroadcastAppendResult, error)) *MockBroadcaster_Broadcast_Call { + _c.Call.Return(run) + return _c +} + +// Close provides a mock function with no fields +func (_m *MockBroadcaster) Close() { + _m.Called() +} + +// MockBroadcaster_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close' +type MockBroadcaster_Close_Call struct { + *mock.Call +} + +// Close is a helper method to define mock.On call +func (_e *MockBroadcaster_Expecter) Close() *MockBroadcaster_Close_Call { + return &MockBroadcaster_Close_Call{Call: _e.mock.On("Close")} +} + +func (_c *MockBroadcaster_Close_Call) Run(run func()) *MockBroadcaster_Close_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockBroadcaster_Close_Call) Return() *MockBroadcaster_Close_Call { + _c.Call.Return() + return _c +} + +func (_c *MockBroadcaster_Close_Call) RunAndReturn(run func()) *MockBroadcaster_Close_Call { + _c.Run(run) + return _c +} + +// LegacyAck provides a mock function with given fields: ctx, broadcastID, vchannel +func (_m *MockBroadcaster) LegacyAck(ctx context.Context, broadcastID uint64, vchannel string) error { + ret := _m.Called(ctx, broadcastID, vchannel) + + if len(ret) == 0 { + panic("no return value specified for LegacyAck") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, uint64, string) error); ok { + r0 = rf(ctx, broadcastID, vchannel) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockBroadcaster_LegacyAck_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'LegacyAck' +type MockBroadcaster_LegacyAck_Call struct { + *mock.Call +} + +// LegacyAck is a helper method to define mock.On call +// - ctx context.Context +// - broadcastID uint64 +// - vchannel string +func (_e *MockBroadcaster_Expecter) LegacyAck(ctx interface{}, broadcastID interface{}, vchannel interface{}) *MockBroadcaster_LegacyAck_Call { + return &MockBroadcaster_LegacyAck_Call{Call: _e.mock.On("LegacyAck", ctx, broadcastID, vchannel)} +} + +func (_c *MockBroadcaster_LegacyAck_Call) Run(run func(ctx context.Context, broadcastID uint64, vchannel string)) *MockBroadcaster_LegacyAck_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(uint64), args[2].(string)) + }) + return _c +} + +func (_c *MockBroadcaster_LegacyAck_Call) Return(_a0 error) *MockBroadcaster_LegacyAck_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockBroadcaster_LegacyAck_Call) RunAndReturn(run func(context.Context, uint64, string) error) *MockBroadcaster_LegacyAck_Call { + _c.Call.Return(run) + return _c +} + +// NewMockBroadcaster creates a new instance of MockBroadcaster. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockBroadcaster(t interface { + mock.TestingT + Cleanup(func()) +}) *MockBroadcaster { + mock := &MockBroadcaster{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/internal/mocks/streamingnode/client/mock_handler/mock_HandlerClient.go b/internal/mocks/streamingnode/client/mock_handler/mock_HandlerClient.go index 85fc9f7182..2bd1397428 100644 --- a/internal/mocks/streamingnode/client/mock_handler/mock_HandlerClient.go +++ b/internal/mocks/streamingnode/client/mock_handler/mock_HandlerClient.go @@ -9,6 +9,8 @@ import ( mock "github.com/stretchr/testify/mock" types "github.com/milvus-io/milvus/pkg/v2/streaming/util/types" + + wal "github.com/milvus-io/milvus/internal/streamingnode/server/wal" ) // MockHandlerClient is an autogenerated mock type for the HandlerClient type @@ -231,6 +233,65 @@ func (_c *MockHandlerClient_GetLatestMVCCTimestampIfLocal_Call) RunAndReturn(run return _c } +// GetReplicateCheckpoint provides a mock function with given fields: ctx, channelName +func (_m *MockHandlerClient) GetReplicateCheckpoint(ctx context.Context, channelName string) (*wal.ReplicateCheckpoint, error) { + ret := _m.Called(ctx, channelName) + + if len(ret) == 0 { + panic("no return value specified for GetReplicateCheckpoint") + } + + var r0 *wal.ReplicateCheckpoint + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) (*wal.ReplicateCheckpoint, error)); ok { + return rf(ctx, channelName) + } + if rf, ok := ret.Get(0).(func(context.Context, string) *wal.ReplicateCheckpoint); ok { + r0 = rf(ctx, channelName) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*wal.ReplicateCheckpoint) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, channelName) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockHandlerClient_GetReplicateCheckpoint_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetReplicateCheckpoint' +type MockHandlerClient_GetReplicateCheckpoint_Call struct { + *mock.Call +} + +// GetReplicateCheckpoint is a helper method to define mock.On call +// - ctx context.Context +// - channelName string +func (_e *MockHandlerClient_Expecter) GetReplicateCheckpoint(ctx interface{}, channelName interface{}) *MockHandlerClient_GetReplicateCheckpoint_Call { + return &MockHandlerClient_GetReplicateCheckpoint_Call{Call: _e.mock.On("GetReplicateCheckpoint", ctx, channelName)} +} + +func (_c *MockHandlerClient_GetReplicateCheckpoint_Call) Run(run func(ctx context.Context, channelName string)) *MockHandlerClient_GetReplicateCheckpoint_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string)) + }) + return _c +} + +func (_c *MockHandlerClient_GetReplicateCheckpoint_Call) Return(_a0 *wal.ReplicateCheckpoint, _a1 error) *MockHandlerClient_GetReplicateCheckpoint_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockHandlerClient_GetReplicateCheckpoint_Call) RunAndReturn(run func(context.Context, string) (*wal.ReplicateCheckpoint, error)) *MockHandlerClient_GetReplicateCheckpoint_Call { + _c.Call.Return(run) + return _c +} + // GetWALMetricsIfLocal provides a mock function with given fields: ctx func (_m *MockHandlerClient) GetWALMetricsIfLocal(ctx context.Context) (*types.StreamingNodeMetrics, error) { ret := _m.Called(ctx) diff --git a/internal/mocks/streamingnode/server/mock_wal/mock_OpenerBuilder.go b/internal/mocks/streamingnode/server/mock_wal/mock_OpenerBuilder.go index 5dec8e7926..3cf4055240 100644 --- a/internal/mocks/streamingnode/server/mock_wal/mock_OpenerBuilder.go +++ b/internal/mocks/streamingnode/server/mock_wal/mock_OpenerBuilder.go @@ -3,8 +3,10 @@ package mock_wal import ( - wal "github.com/milvus-io/milvus/internal/streamingnode/server/wal" + message "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" mock "github.com/stretchr/testify/mock" + + wal "github.com/milvus-io/milvus/internal/streamingnode/server/wal" ) // MockOpenerBuilder is an autogenerated mock type for the OpenerBuilder type @@ -78,18 +80,18 @@ func (_c *MockOpenerBuilder_Build_Call) RunAndReturn(run func() (wal.Opener, err } // Name provides a mock function with no fields -func (_m *MockOpenerBuilder) Name() string { +func (_m *MockOpenerBuilder) Name() message.WALName { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for Name") } - var r0 string - if rf, ok := ret.Get(0).(func() string); ok { + var r0 message.WALName + if rf, ok := ret.Get(0).(func() message.WALName); ok { r0 = rf() } else { - r0 = ret.Get(0).(string) + r0 = ret.Get(0).(message.WALName) } return r0 @@ -112,12 +114,12 @@ func (_c *MockOpenerBuilder_Name_Call) Run(run func()) *MockOpenerBuilder_Name_C return _c } -func (_c *MockOpenerBuilder_Name_Call) Return(_a0 string) *MockOpenerBuilder_Name_Call { +func (_c *MockOpenerBuilder_Name_Call) Return(_a0 message.WALName) *MockOpenerBuilder_Name_Call { _c.Call.Return(_a0) return _c } -func (_c *MockOpenerBuilder_Name_Call) RunAndReturn(run func() string) *MockOpenerBuilder_Name_Call { +func (_c *MockOpenerBuilder_Name_Call) RunAndReturn(run func() message.WALName) *MockOpenerBuilder_Name_Call { _c.Call.Return(run) return _c } diff --git a/internal/mocks/streamingnode/server/mock_wal/mock_WAL.go b/internal/mocks/streamingnode/server/mock_wal/mock_WAL.go index bf24a5ba7b..6a74cf209a 100644 --- a/internal/mocks/streamingnode/server/mock_wal/mock_WAL.go +++ b/internal/mocks/streamingnode/server/mock_wal/mock_WAL.go @@ -453,18 +453,18 @@ func (_c *MockWAL_Read_Call) RunAndReturn(run func(context.Context, wal.ReadOpti } // WALName provides a mock function with no fields -func (_m *MockWAL) WALName() string { +func (_m *MockWAL) WALName() message.WALName { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for WALName") } - var r0 string - if rf, ok := ret.Get(0).(func() string); ok { + var r0 message.WALName + if rf, ok := ret.Get(0).(func() message.WALName); ok { r0 = rf() } else { - r0 = ret.Get(0).(string) + r0 = ret.Get(0).(message.WALName) } return r0 @@ -487,12 +487,12 @@ func (_c *MockWAL_WALName_Call) Run(run func()) *MockWAL_WALName_Call { return _c } -func (_c *MockWAL_WALName_Call) Return(_a0 string) *MockWAL_WALName_Call { +func (_c *MockWAL_WALName_Call) Return(_a0 message.WALName) *MockWAL_WALName_Call { _c.Call.Return(_a0) return _c } -func (_c *MockWAL_WALName_Call) RunAndReturn(run func() string) *MockWAL_WALName_Call { +func (_c *MockWAL_WALName_Call) RunAndReturn(run func() message.WALName) *MockWAL_WALName_Call { _c.Call.Return(run) return _c } diff --git a/internal/proxy/impl.go b/internal/proxy/impl.go index 0c05b2ab9f..9305e6caf3 100644 --- a/internal/proxy/impl.go +++ b/internal/proxy/impl.go @@ -40,8 +40,10 @@ import ( "github.com/milvus-io/milvus-proto/go-api/v2/milvuspb" "github.com/milvus-io/milvus-proto/go-api/v2/msgpb" "github.com/milvus-io/milvus-proto/go-api/v2/schemapb" + "github.com/milvus-io/milvus/internal/distributed/streaming" "github.com/milvus-io/milvus/internal/http" "github.com/milvus-io/milvus/internal/proxy/connection" + "github.com/milvus-io/milvus/internal/proxy/replicate" "github.com/milvus-io/milvus/internal/types" "github.com/milvus-io/milvus/internal/util/analyzer" "github.com/milvus-io/milvus/internal/util/hookutil" @@ -62,6 +64,7 @@ import ( "github.com/milvus-io/milvus/pkg/v2/util/metricsinfo" "github.com/milvus-io/milvus/pkg/v2/util/paramtable" "github.com/milvus-io/milvus/pkg/v2/util/ratelimitutil" + "github.com/milvus-io/milvus/pkg/v2/util/replicateutil" "github.com/milvus-io/milvus/pkg/v2/util/requestutil" "github.com/milvus-io/milvus/pkg/v2/util/retry" "github.com/milvus-io/milvus/pkg/v2/util/timerecord" @@ -1737,7 +1740,7 @@ func (node *Proxy) GetLoadingProgress(ctx context.Context, request *milvuspb.Get }, nil } -func (node *Proxy) GetLoadState(ctx context.Context, request *milvuspb.GetLoadStateRequest) (*milvuspb.GetLoadStateResponse, error) { +func (node *Proxy) GetLoadState(ctx context.Context, request *milvuspb.GetLoadStateRequest) (resp *milvuspb.GetLoadStateResponse, err error) { if err := merr.CheckHealthy(node.GetStateCode()); err != nil { return &milvuspb.GetLoadStateResponse{Status: merr.Status(err)}, nil } @@ -1771,7 +1774,10 @@ func (node *Proxy) GetLoadState(ctx context.Context, request *milvuspb.GetLoadSt defer func() { log.Debug( rpcDone(method), - zap.Any("request", request)) + zap.Any("request", request), + zap.Any("response", resp), + zap.Error(err), + ) metrics.ProxyReqLatency.WithLabelValues(strconv.FormatInt(paramtable.GetNodeID(), 10), method).Observe(float64(tr.ElapseSpan().Milliseconds())) }() @@ -6445,3 +6451,86 @@ func (node *Proxy) ListFileResources(ctx context.Context, req *milvuspb.ListFile log.Info("ListFileResources success", zap.Int("count", len(resp.GetResources()))) return resp, nil } + +// UpdateReplicateConfiguration applies a full replacement of the current replication configuration across Milvus clusters. +func (node *Proxy) UpdateReplicateConfiguration(ctx context.Context, req *milvuspb.UpdateReplicateConfigurationRequest) (*commonpb.Status, error) { + ctx, sp := otel.Tracer(typeutil.ProxyRole).Start(ctx, "Proxy-UpdateReplicateConfiguration") + defer sp.End() + + if err := merr.CheckHealthy(node.GetStateCode()); err != nil { + return merr.Status(err), nil + } + log.Ctx(ctx).Info("UpdateReplicateConfiguration received", replicateutil.ConfigLogFields(req.GetReplicateConfiguration())...) + err := streaming.WAL().Replicate().UpdateReplicateConfiguration(ctx, req.GetReplicateConfiguration()) + if err != nil { + log.Ctx(ctx).Warn("UpdateReplicateConfiguration fail", zap.Error(err)) + return merr.Status(err), nil + } + log.Ctx(ctx).Info("UpdateReplicateConfiguration success", replicateutil.ConfigLogFields(req.GetReplicateConfiguration())...) + return merr.Status(nil), nil +} + +// GetReplicateInfo retrieves replication-related metadata from a target Milvus cluster. +// TODO: sheep, only get target checkpoint +func (node *Proxy) GetReplicateInfo(ctx context.Context, req *milvuspb.GetReplicateInfoRequest) (resp *milvuspb.GetReplicateInfoResponse, err error) { + ctx, sp := otel.Tracer(typeutil.ProxyRole).Start(ctx, "Proxy-GetReplicateInfo") + defer sp.End() + + if err := merr.CheckHealthy(node.GetStateCode()); err != nil { + return nil, err + } + + logger := log.Ctx(ctx).With(zap.String("sourceClusterID", req.GetSourceClusterId())) + logger.Info("GetReplicateInfo received") + defer func() { + if err != nil { + logger.Warn("GetReplicateInfo fail", zap.Error(err)) + } else { + logger.Info("GetReplicateInfo success", zap.Any("checkpoints", resp.GetCheckpoints())) + } + }() + + configHelper, err := streaming.WAL().Replicate().GetReplicateConfiguration(ctx) + if err != nil { + return nil, err + } + currentCluster := configHelper.GetCurrentCluster() + + checkpoints := make([]*commonpb.ReplicateCheckpoint, 0, len(currentCluster.GetPchannels())) + for _, pchannel := range currentCluster.GetPchannels() { + checkpoint, err := streaming.WAL().Replicate().GetReplicateCheckpoint(ctx, pchannel) + if err != nil { + return nil, err + } + checkpoints = append(checkpoints, checkpoint.IntoProto()) + } + return &milvuspb.GetReplicateInfoResponse{ + Checkpoints: checkpoints, + }, nil +} + +// CreateReplicateStream establishes a replication stream on the target Milvus cluster. +func (node *Proxy) CreateReplicateStream(stream milvuspb.MilvusService_CreateReplicateStreamServer) (err error) { + ctx := stream.Context() + ctx, sp := otel.Tracer(typeutil.ProxyRole).Start(ctx, "Proxy-CreateReplicateStream") + defer sp.End() + + if err := merr.CheckHealthy(node.GetStateCode()); err != nil { + return err + } + + log.Ctx(ctx).Info("replicate stream created") + defer func() { + if err != nil { + log.Ctx(ctx).Warn("replicate stream closed with error", zap.Error(err)) + } else { + log.Ctx(ctx).Info("replicate stream closed") + } + }() + + s, err := replicate.CreateReplicateServer(stream) + if err != nil { + return err + } + return s.Execute() +} diff --git a/internal/proxy/proxy.go b/internal/proxy/proxy.go index e4cae39a7e..ec39650c38 100644 --- a/internal/proxy/proxy.go +++ b/internal/proxy/proxy.go @@ -41,7 +41,6 @@ import ( "github.com/milvus-io/milvus/pkg/v2/log" "github.com/milvus-io/milvus/pkg/v2/metrics" "github.com/milvus-io/milvus/pkg/v2/proto/internalpb" - "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" "github.com/milvus-io/milvus/pkg/v2/util/expr" "github.com/milvus-io/milvus/pkg/v2/util/logutil" "github.com/milvus-io/milvus/pkg/v2/util/metricsinfo" @@ -263,10 +262,6 @@ func (node *Proxy) Init() error { uuid.EnableRandPool() log.Debug("enable rand pool for UUIDv4 generation") - if hookutil.IsClusterEncyptionEnabled() { - message.RegisterCipher(hookutil.GetCipher()) - } - log.Info("init proxy done", zap.Int64("nodeID", paramtable.GetNodeID()), zap.String("Address", node.address)) return nil } diff --git a/internal/proxy/replicate/replicate_stream_server.go b/internal/proxy/replicate/replicate_stream_server.go new file mode 100644 index 0000000000..adc3b37ea9 --- /dev/null +++ b/internal/proxy/replicate/replicate_stream_server.go @@ -0,0 +1,159 @@ +package replicate + +import ( + "io" + "sync" + + "github.com/cockroachdb/errors" + "go.uber.org/zap" + + "github.com/milvus-io/milvus-proto/go-api/v2/milvuspb" + "github.com/milvus-io/milvus/internal/distributed/streaming" + "github.com/milvus-io/milvus/internal/util/streamingutil/service/contextutil" + "github.com/milvus-io/milvus/internal/util/streamingutil/status" + "github.com/milvus-io/milvus/pkg/v2/log" + "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" +) + +const replicateRespChanLength = 128 + +func CreateReplicateServer(streamServer milvuspb.MilvusService_CreateReplicateStreamServer) (*ReplicateStreamServer, error) { + clusterID, err := contextutil.GetClusterID(streamServer.Context()) + if err != nil { + return nil, err + } + return &ReplicateStreamServer{ + clusterID: clusterID, + streamServer: streamServer, + replicateRespCh: make(chan *milvuspb.ReplicateResponse, replicateRespChanLength), + wg: sync.WaitGroup{}, + }, nil +} + +// ReplicateStreamServer is a ReplicateStreamServer of replicate messages. +type ReplicateStreamServer struct { + clusterID string + streamServer milvuspb.MilvusService_CreateReplicateStreamServer + replicateRespCh chan *milvuspb.ReplicateResponse // All processing messages result should sent from theses channel. + wg sync.WaitGroup +} + +// Execute starts the replicate server. +func (p *ReplicateStreamServer) Execute() error { + // Start a recv arm to handle the control message from client. + go func() { + // recv loop will be blocked until the stream is closed. + _ = p.recvLoop() + }() + + // Start a send loop on current main goroutine. + // the loop will be blocked until the stream is closed. + err := p.sendLoop() + return err +} + +// sendLoop sends the message to client. +func (p *ReplicateStreamServer) sendLoop() (err error) { + defer func() { + if err != nil { + log.Warn("send arm of stream closed by unexpected error", zap.Error(err)) + return + } + log.Info("send arm of stream closed") + }() + + for { + select { + case resp, ok := <-p.replicateRespCh: + if !ok { + return nil + } + if err := p.streamServer.Send(resp); err != nil { + return err + } + case <-p.streamServer.Context().Done(): + return errors.Wrap(p.streamServer.Context().Err(), "cancel send loop by stream server") + } + } +} + +// recvLoop receives the message from client. +func (p *ReplicateStreamServer) recvLoop() (err error) { + defer func() { + p.wg.Wait() + close(p.replicateRespCh) + if err != nil { + log.Warn("recv arm of stream closed by unexpected error", zap.Error(err)) + return + } + log.Info("recv arm of stream closed") + }() + + for { + req, err := p.streamServer.Recv() + if err == io.EOF { + return nil + } + if err != nil { + return err + } + switch req := req.Request.(type) { + case *milvuspb.ReplicateRequest_ReplicateMessage: + err := p.handleReplicateMessage(req) + if err != nil { + return err + } + default: + log.Warn("unknown request type", zap.Any("request", req)) + } + } +} + +// handleReplicateMessage handles the replicate message request. +func (p *ReplicateStreamServer) handleReplicateMessage(req *milvuspb.ReplicateRequest_ReplicateMessage) error { + // TODO: sheep, update metrics. + p.wg.Add(1) + defer p.wg.Done() + reqMsg := req.ReplicateMessage.GetMessage() + msg := message.NewReplicateMessage(req.ReplicateMessage.SourceClusterId, reqMsg) + sourceTs := msg.ReplicateHeader().TimeTick + log.Debug("recv replicate message from client", + zap.String("messageID", reqMsg.GetId().GetId()), + zap.Uint64("sourceTimeTick", sourceTs), + log.FieldMessage(msg), + ) + + // Append message to wal. + _, err := streaming.WAL().Replicate().Append(p.streamServer.Context(), msg) + if err == nil { + p.sendReplicateResult(sourceTs) + return nil + } + if status.AsStreamingError(err).IsIgnoredOperation() { + log.Info("append replicate message to wal ignored", log.FieldMessage(msg), zap.Error(err)) + return nil + } + // unexpected error, will close the stream and wait for client to reconnect. + log.Warn("append replicate message to wal failed", log.FieldMessage(msg), zap.Error(err)) + return err +} + +// sendReplicateResult sends the replicate result to client. +func (p *ReplicateStreamServer) sendReplicateResult(sourceTimeTick uint64) { + resp := &milvuspb.ReplicateResponse{ + Response: &milvuspb.ReplicateResponse_ReplicateConfirmedMessageInfo{ + ReplicateConfirmedMessageInfo: &milvuspb.ReplicateConfirmedMessageInfo{ + ConfirmedTimeTick: sourceTimeTick, + }, + }, + } + // If server context is canceled, it means the stream has been closed. + // all pending response message should be dropped, client side will handle it. + select { + case p.replicateRespCh <- resp: + log.Debug("send replicate message response to client", zap.Uint64("confirmedTimeTick", sourceTimeTick)) + case <-p.streamServer.Context().Done(): + log.Warn("stream closed before replicate message response sent", zap.Uint64("confirmedTimeTick", sourceTimeTick)) + return + } +} diff --git a/internal/proxy/replicate/replicate_stream_server_test.go b/internal/proxy/replicate/replicate_stream_server_test.go new file mode 100644 index 0000000000..d9ef4e4f4d --- /dev/null +++ b/internal/proxy/replicate/replicate_stream_server_test.go @@ -0,0 +1,237 @@ +package replicate + +import ( + "context" + "io" + "sync" + "testing" + "time" + + "github.com/apache/pulsar-client-go/pulsar" + "github.com/cockroachdb/errors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "google.golang.org/grpc/metadata" + + "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" + "github.com/milvus-io/milvus-proto/go-api/v2/milvuspb" + "github.com/milvus-io/milvus-proto/go-api/v2/msgpb" + "github.com/milvus-io/milvus/internal/distributed/streaming" + "github.com/milvus-io/milvus/internal/mocks/distributed/mock_streaming" + "github.com/milvus-io/milvus/pkg/v2/proto/messagespb" + "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" + "github.com/milvus-io/milvus/pkg/v2/streaming/util/types" + pulsar2 "github.com/milvus-io/milvus/pkg/v2/streaming/walimpls/impls/pulsar" +) + +// createContextWithClusterID creates a context with cluster ID in metadata (simulating incoming context) +func createContextWithClusterID(clusterID string) context.Context { + if clusterID == "" { + return context.Background() + } + md := metadata.New(map[string]string{ + "cluster-id": clusterID, + }) + return metadata.NewIncomingContext(context.Background(), md) +} + +func TestReplicateStreamServer_Execute(t *testing.T) { + ctx := createContextWithClusterID("test-cluster") + mockStreamServer := newMockReplicateStreamServer(ctx) + + const msgCount = replicateRespChanLength * 10 + + // Setup WAL mock + replicateService := mock_streaming.NewMockReplicateService(t) + tt := uint64(1) + replicateService.EXPECT().Append(mock.Anything, mock.Anything). + RunAndReturn(func(ctx context.Context, msg message.ReplicateMutableMessage) (*types.AppendResult, error) { + defer func() { tt++ }() + return &types.AppendResult{ + TimeTick: tt, + }, nil + }) + mockWAL := mock_streaming.NewMockWALAccesser(t) + mockWAL.EXPECT().Replicate().Return(replicateService) + streaming.SetWALForTest(mockWAL) + + server, err := CreateReplicateServer(mockStreamServer) + assert.NoError(t, err) + + wg := sync.WaitGroup{} + wg.Add(1) + go func() { + defer wg.Done() + err := server.Execute() + assert.NoError(t, err) + }() + + wg.Add(1) + go func() { + defer wg.Done() + for i := 0; i < msgCount; i++ { + tt := uint64(i + 1) + messageID := pulsar2.NewPulsarID(pulsar.EarliestMessageID()) + msg := message.NewInsertMessageBuilderV1(). + WithVChannel("test-vchannel"). + WithHeader(&messagespb.InsertMessageHeader{}). + WithBody(&msgpb.InsertRequest{}). + MustBuildMutable().WithTimeTick(tt). + WithLastConfirmed(messageID) + milvusMsg := message.ImmutableMessageToMilvusMessage(commonpb.WALName_Pulsar.String(), msg.IntoImmutableMessage(messageID)) + mockStreamServer.SendRequest(&milvuspb.ReplicateRequest{ + Request: &milvuspb.ReplicateRequest_ReplicateMessage{ + ReplicateMessage: &milvuspb.ReplicateMessage{ + Message: milvusMsg, + }, + }, + }) + } + }() + + for i := 0; i < msgCount; i++ { + tt := uint64(i + 1) + sentResp := mockStreamServer.GetSentResponse() + assert.NotNil(t, sentResp) + assert.Equal(t, tt, sentResp.GetReplicateConfirmedMessageInfo().GetConfirmedTimeTick()) + } + + // Close the stream to stop execution + mockStreamServer.CloseSend() + wg.Wait() +} + +func TestReplicateStreamServer_ContextCanceled(t *testing.T) { + ctx, cancel := context.WithCancel(createContextWithClusterID("test-cluster")) + mockStreamServer := newMockReplicateStreamServer(ctx) + + server, err := CreateReplicateServer(mockStreamServer) + assert.NoError(t, err) + + // Test send loop with canceled context + wg := sync.WaitGroup{} + wg.Add(1) + go func() { + defer wg.Done() + err := server.Execute() + assert.Error(t, err) + assert.True(t, errors.Is(err, context.Canceled)) + }() + + // Cancel context + cancel() + wg.Wait() +} + +func TestReplicateStreamServer_recvLoop_RecvError(t *testing.T) { + ctx := createContextWithClusterID("test-cluster") + mockStreamServer := newMockReplicateStreamServer(ctx) + mockStreamServer.recvError = errors.New("recv error") + + server, err := CreateReplicateServer(mockStreamServer) + assert.NoError(t, err) + + // Test recv loop with recv error + wg := sync.WaitGroup{} + wg.Add(1) + go func() { + defer wg.Done() + err := server.recvLoop() + assert.Error(t, err) + assert.Equal(t, "recv error", err.Error()) + }() + + wg.Wait() +} + +// mockReplicateStreamServer implements the milvuspb.MilvusService_CreateReplicateStreamServer interface +type mockReplicateStreamServer struct { + ctx context.Context + sendError error + recvError error + recvRequests chan *milvuspb.ReplicateRequest + sentResponses chan *milvuspb.ReplicateResponse + closeCh chan struct{} + timeout time.Duration +} + +func newMockReplicateStreamServer(ctx context.Context) *mockReplicateStreamServer { + return &mockReplicateStreamServer{ + ctx: ctx, + recvRequests: make(chan *milvuspb.ReplicateRequest, 128), + sentResponses: make(chan *milvuspb.ReplicateResponse, 128), + closeCh: make(chan struct{}, 1), + timeout: 10 * time.Second, + } +} + +func (m *mockReplicateStreamServer) Send(resp *milvuspb.ReplicateResponse) error { + if m.sendError != nil { + return m.sendError + } + m.sentResponses <- resp + return nil +} + +func (m *mockReplicateStreamServer) Recv() (*milvuspb.ReplicateRequest, error) { + if m.recvError != nil { + return nil, m.recvError + } + select { + case <-m.closeCh: + return nil, io.EOF + case req := <-m.recvRequests: + return req, nil + case <-time.After(m.timeout): + return nil, errors.New("recv timeout") + } +} + +func (m *mockReplicateStreamServer) RecvMsg(msg interface{}) error { + return nil +} + +func (m *mockReplicateStreamServer) SendMsg(msg interface{}) error { + return nil +} + +func (m *mockReplicateStreamServer) Header() (metadata.MD, error) { + return nil, nil +} + +func (m *mockReplicateStreamServer) Trailer() metadata.MD { + return nil +} + +func (m *mockReplicateStreamServer) SendHeader(md metadata.MD) error { + return nil +} + +func (m *mockReplicateStreamServer) SetHeader(md metadata.MD) error { + return nil +} + +func (m *mockReplicateStreamServer) SetTrailer(md metadata.MD) { +} + +func (m *mockReplicateStreamServer) Context() context.Context { + return m.ctx +} + +func (m *mockReplicateStreamServer) CloseSend() error { + close(m.closeCh) + return nil +} + +func (m *mockReplicateStreamServer) SendRequest(req *milvuspb.ReplicateRequest) { + m.recvRequests <- req +} + +func (m *mockReplicateStreamServer) GetSentResponse() *milvuspb.ReplicateResponse { + select { + case resp := <-m.sentResponses: + return resp + case <-time.After(m.timeout): + return nil + } +} diff --git a/internal/querynodev2/server.go b/internal/querynodev2/server.go index fe8332f55a..8e5c04ec9f 100644 --- a/internal/querynodev2/server.go +++ b/internal/querynodev2/server.go @@ -72,7 +72,7 @@ import ( "github.com/milvus-io/milvus/pkg/v2/metrics" "github.com/milvus-io/milvus/pkg/v2/mq/msgdispatcher" "github.com/milvus-io/milvus/pkg/v2/proto/datapb" - "github.com/milvus-io/milvus/pkg/v2/streaming/walimpls/impls/rmq" + "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" "github.com/milvus-io/milvus/pkg/v2/util/expr" "github.com/milvus-io/milvus/pkg/v2/util/hardware" "github.com/milvus-io/milvus/pkg/v2/util/lifetime" @@ -539,7 +539,7 @@ func (node *QueryNode) Stop() error { err := node.session.GoingStop() if err != nil { log.Warn("session fail to go stopping state", zap.Error(err)) - } else if util.MustSelectWALName() != rmq.WALName { // rocksmq cannot support querynode graceful stop because of using local storage. + } else if util.MustSelectWALName() != message.WALNameRocksmq { // rocksmq cannot support querynode graceful stop because of using local storage. metrics.StoppingBalanceNodeNum.WithLabelValues().Set(1) // TODO: Redundant timeout control, graceful stop timeout is controlled by outside by `component`. // Integration test is still using it, Remove it in future. diff --git a/internal/querynodev2/services_test.go b/internal/querynodev2/services_test.go index e87780e37a..c0975d0d21 100644 --- a/internal/querynodev2/services_test.go +++ b/internal/querynodev2/services_test.go @@ -46,6 +46,7 @@ import ( "github.com/milvus-io/milvus/internal/querynodev2/segments" "github.com/milvus-io/milvus/internal/storage" "github.com/milvus-io/milvus/internal/util/dependency" + "github.com/milvus-io/milvus/internal/util/streamingutil/util" "github.com/milvus-io/milvus/internal/util/streamrpc" "github.com/milvus-io/milvus/pkg/v2/common" "github.com/milvus-io/milvus/pkg/v2/log" @@ -53,8 +54,8 @@ import ( "github.com/milvus-io/milvus/pkg/v2/proto/indexpb" "github.com/milvus-io/milvus/pkg/v2/proto/internalpb" "github.com/milvus-io/milvus/pkg/v2/proto/querypb" + "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" "github.com/milvus-io/milvus/pkg/v2/streaming/util/types" - "github.com/milvus-io/milvus/pkg/v2/streaming/walimpls/impls/rmq" "github.com/milvus-io/milvus/pkg/v2/util/conc" "github.com/milvus-io/milvus/pkg/v2/util/etcd" "github.com/milvus-io/milvus/pkg/v2/util/funcutil" @@ -2420,12 +2421,14 @@ func TestQueryNodeService(t *testing.T) { local.EXPECT().GetLatestMVCCTimestampIfLocal(mock.Anything, mock.Anything).Return(0, nil).Maybe() local.EXPECT().GetMetricsIfLocal(mock.Anything).Return(&types.StreamingNodeMetrics{}, nil).Maybe() wal.EXPECT().Local().Return(local).Maybe() - wal.EXPECT().WALName().Return(rmq.WALName).Maybe() scanner := mock_streaming.NewMockScanner(t) scanner.EXPECT().Done().Return(make(chan struct{})).Maybe() scanner.EXPECT().Error().Return(nil).Maybe() scanner.EXPECT().Close().Return().Maybe() wal.EXPECT().Read(mock.Anything, mock.Anything).Return(scanner).Maybe() + paramtable.SetRole(typeutil.StandaloneRole) + paramtable.Get().MQCfg.Type.SwapTempValue(message.WALNameRocksmq.String()) + util.InitAndSelectWALName() streaming.SetWALForTest(wal) defer streaming.RecoverWALForTest() diff --git a/internal/streamingcoord/client/assignment/assignment_impl.go b/internal/streamingcoord/client/assignment/assignment_impl.go index 4f8097d7f0..0c1b1b3fdd 100644 --- a/internal/streamingcoord/client/assignment/assignment_impl.go +++ b/internal/streamingcoord/client/assignment/assignment_impl.go @@ -8,11 +8,13 @@ import ( "github.com/cockroachdb/errors" "go.uber.org/zap" + "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" "github.com/milvus-io/milvus/internal/util/streamingutil/service/lazygrpc" "github.com/milvus-io/milvus/internal/util/streamingutil/status" "github.com/milvus-io/milvus/pkg/v2/log" "github.com/milvus-io/milvus/pkg/v2/proto/streamingpb" "github.com/milvus-io/milvus/pkg/v2/streaming/util/types" + "github.com/milvus-io/milvus/pkg/v2/util/replicateutil" "github.com/milvus-io/milvus/pkg/v2/util/syncutil" "github.com/milvus-io/milvus/pkg/v2/util/typeutil" ) @@ -96,6 +98,32 @@ func (c *AssignmentServiceImpl) ReportAssignmentError(ctx context.Context, pchan return nil } +// UpdateReplicateConfiguration updates the replicate configuration to the milvus cluster. +func (c *AssignmentServiceImpl) UpdateReplicateConfiguration(ctx context.Context, config *commonpb.ReplicateConfiguration) error { + if !c.lifetime.Add(typeutil.LifetimeStateWorking) { + return status.NewOnShutdownError("assignment service client is closing") + } + defer c.lifetime.Done() + + service, err := c.service.GetService(c.ctx) + if err != nil { + return err + } + _, err = service.UpdateReplicateConfiguration(ctx, &streamingpb.UpdateReplicateConfigurationRequest{ + Configuration: config, + }) + return err +} + +func (c *AssignmentServiceImpl) GetReplicateConfiguration(ctx context.Context) (*replicateutil.ConfigHelper, error) { + if !c.lifetime.Add(typeutil.LifetimeStateWorking) { + return nil, status.NewOnShutdownError("assignment service client is closing") + } + defer c.lifetime.Done() + + return c.watcher.GetLatestReplicateConfiguration(ctx) +} + // Close closes the assignment service. func (c *AssignmentServiceImpl) Close() { c.lifetime.SetState(typeutil.LifetimeStateStopped) diff --git a/internal/streamingcoord/client/assignment/assignment_test.go b/internal/streamingcoord/client/assignment/assignment_test.go index af249bcd8b..fef314180c 100644 --- a/internal/streamingcoord/client/assignment/assignment_test.go +++ b/internal/streamingcoord/client/assignment/assignment_test.go @@ -15,10 +15,13 @@ import ( "github.com/milvus-io/milvus/pkg/v2/mocks/proto/mock_streamingpb" "github.com/milvus-io/milvus/pkg/v2/proto/streamingpb" "github.com/milvus-io/milvus/pkg/v2/streaming/util/types" + "github.com/milvus-io/milvus/pkg/v2/util/paramtable" "github.com/milvus-io/milvus/pkg/v2/util/typeutil" ) func TestAssignmentService(t *testing.T) { + paramtable.Init() + s := mock_lazygrpc.NewMockService[streamingpb.StreamingCoordAssignmentServiceClient](t) c := mock_streamingpb.NewMockStreamingCoordAssignmentServiceClient(t) s.EXPECT().GetService(mock.Anything).Return(c, nil) diff --git a/internal/streamingcoord/client/assignment/discoverer.go b/internal/streamingcoord/client/assignment/discoverer.go index 5c20223487..c4bf8ba9a2 100644 --- a/internal/streamingcoord/client/assignment/discoverer.go +++ b/internal/streamingcoord/client/assignment/discoverer.go @@ -8,6 +8,8 @@ import ( "github.com/milvus-io/milvus/pkg/v2/log" "github.com/milvus-io/milvus/pkg/v2/proto/streamingpb" "github.com/milvus-io/milvus/pkg/v2/streaming/util/types" + "github.com/milvus-io/milvus/pkg/v2/util/paramtable" + "github.com/milvus-io/milvus/pkg/v2/util/replicateutil" "github.com/milvus-io/milvus/pkg/v2/util/typeutil" ) @@ -22,6 +24,7 @@ func newAssignmentDiscoverClient(w *watcher, streamClient streamingpb.StreamingC exitCh: make(chan struct{}), wg: sync.WaitGroup{}, lastErrorReportedTerm: make(map[string]int64), + clusterID: paramtable.Get().CommonCfg.ClusterPrefix.GetValue(), } c.executeBackgroundTask() return c @@ -37,6 +40,7 @@ type assignmentDiscoverClient struct { wg sync.WaitGroup streamClient streamingpb.StreamingCoordAssignmentService_AssignmentDiscoverClient lastErrorReportedTerm map[string]int64 + clusterID string } // ReportAssignmentError reports the assignment error to server. @@ -162,6 +166,9 @@ func (c *assignmentDiscoverClient) recvLoop() (err error) { Version: newIncomingVersion, Assignments: newIncomingAssignments, CChannel: resp.FullAssignment.Cchannel, + ReplicateConfigHelper: replicateutil.MustNewConfigHelper( + c.clusterID, + resp.FullAssignment.ReplicateConfiguration), }) case *streamingpb.AssignmentDiscoverResponse_Close: // nothing to do now, just wait io.EOF. diff --git a/internal/streamingcoord/client/assignment/watcher.go b/internal/streamingcoord/client/assignment/watcher.go index f2d1a1bab7..7adb053ebf 100644 --- a/internal/streamingcoord/client/assignment/watcher.go +++ b/internal/streamingcoord/client/assignment/watcher.go @@ -7,6 +7,7 @@ import ( "github.com/cockroachdb/errors" "github.com/milvus-io/milvus/pkg/v2/streaming/util/types" + "github.com/milvus-io/milvus/pkg/v2/util/replicateutil" "github.com/milvus-io/milvus/pkg/v2/util/syncutil" "github.com/milvus-io/milvus/pkg/v2/util/typeutil" ) @@ -18,8 +19,9 @@ func newWatcher() *watcher { return &watcher{ cond: syncutil.NewContextCond(&sync.Mutex{}), lastVersionedAssignment: types.VersionedStreamingNodeAssignments{ - Version: typeutil.VersionInt64Pair{Global: -1, Local: -1}, - Assignments: make(map[int64]types.StreamingNodeAssignment), + Version: typeutil.VersionInt64Pair{Global: -1, Local: -1}, + Assignments: make(map[int64]types.StreamingNodeAssignment), + ReplicateConfigHelper: nil, }, } } @@ -42,6 +44,19 @@ func (w *watcher) GetLatestDiscover(ctx context.Context) (*types.VersionedStream return &last, nil } +func (w *watcher) GetLatestReplicateConfiguration(ctx context.Context) (*replicateutil.ConfigHelper, error) { + w.cond.L.Lock() + for (w.lastVersionedAssignment.Version.Global == -1 && w.lastVersionedAssignment.Version.Local == -1) || + w.lastVersionedAssignment.ReplicateConfigHelper == nil { + if err := w.cond.Wait(ctx); err != nil { + return nil, err + } + } + last := w.lastVersionedAssignment + w.cond.L.Unlock() + return last.ReplicateConfigHelper, nil +} + // AssignmentDiscover watches the assignment discovery. func (w *watcher) AssignmentDiscover(ctx context.Context, cb func(*types.VersionedStreamingNodeAssignments) error) error { w.cond.L.Lock() diff --git a/internal/streamingcoord/client/broadcast/broadcast_impl.go b/internal/streamingcoord/client/broadcast/broadcast_impl.go index deb3da0107..e679abb677 100644 --- a/internal/streamingcoord/client/broadcast/broadcast_impl.go +++ b/internal/streamingcoord/client/broadcast/broadcast_impl.go @@ -10,9 +10,8 @@ import ( ) // NewGRPCBroadcastService creates a new broadcast service with grpc. -func NewGRPCBroadcastService(walName string, service lazygrpc.Service[streamingpb.StreamingCoordBroadcastServiceClient]) *GRPCBroadcastServiceImpl { +func NewGRPCBroadcastService(service lazygrpc.Service[streamingpb.StreamingCoordBroadcastServiceClient]) *GRPCBroadcastServiceImpl { return &GRPCBroadcastServiceImpl{ - walName: walName, service: service, } } @@ -20,7 +19,6 @@ func NewGRPCBroadcastService(walName string, service lazygrpc.Service[streamingp // GRPCBroadcastServiceImpl is the implementation of BroadcastService based on grpc service. // If the streaming coord is not deployed at current node, these implementation will be used. type GRPCBroadcastServiceImpl struct { - walName string service lazygrpc.Service[streamingpb.StreamingCoordBroadcastServiceClient] } @@ -37,7 +35,7 @@ func (c *GRPCBroadcastServiceImpl) Broadcast(ctx context.Context, msg message.Br } results := make(map[string]*types.AppendResult, len(resp.Results)) for channel, result := range resp.Results { - msgID, err := message.UnmarshalMessageID(c.walName, result.Id.Id) + msgID, err := message.UnmarshalMessageID(result.Id) if err != nil { return nil, err } diff --git a/internal/streamingcoord/client/broadcast/broadcast_test.go b/internal/streamingcoord/client/broadcast/broadcast_test.go index 2005bc0e09..47a6aa7fdb 100644 --- a/internal/streamingcoord/client/broadcast/broadcast_test.go +++ b/internal/streamingcoord/client/broadcast/broadcast_test.go @@ -12,7 +12,6 @@ import ( "github.com/milvus-io/milvus/internal/mocks/util/streamingutil/service/mock_lazygrpc" "github.com/milvus-io/milvus/internal/util/streamingutil/service/lazygrpc" "github.com/milvus-io/milvus/pkg/v2/mocks/proto/mock_streamingpb" - "github.com/milvus-io/milvus/pkg/v2/proto/messagespb" "github.com/milvus-io/milvus/pkg/v2/proto/streamingpb" "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" "github.com/milvus-io/milvus/pkg/v2/streaming/walimpls/impls/rmq" @@ -21,7 +20,7 @@ import ( func TestBroadcast(t *testing.T) { s := newMockServer(t, 0) - bs := NewGRPCBroadcastService(walimplstest.WALName, s) + bs := NewGRPCBroadcastService(s) msg := message.NewDropCollectionMessageBuilderV1(). WithHeader(&message.DropCollectionMessageHeader{}). WithBody(&msgpb.DropCollectionRequest{}). @@ -42,9 +41,7 @@ func newMockServer(t *testing.T, sendDelay time.Duration) lazygrpc.Service[strea c.EXPECT().Broadcast(mock.Anything, mock.Anything).Return(&streamingpb.BroadcastResponse{ Results: map[string]*streamingpb.ProduceMessageResponseResult{ "v1": { - Id: &messagespb.MessageID{ - Id: walimplstest.NewTestMessageID(1).Marshal(), - }, + Id: walimplstest.NewTestMessageID(1).IntoProto(), }, }, BroadcastId: 1, diff --git a/internal/streamingcoord/client/client.go b/internal/streamingcoord/client/client.go index 6c8ee7d5e9..8e66c947d1 100644 --- a/internal/streamingcoord/client/client.go +++ b/internal/streamingcoord/client/client.go @@ -8,6 +8,7 @@ import ( "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" "google.golang.org/grpc" + "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" "github.com/milvus-io/milvus/internal/json" "github.com/milvus-io/milvus/internal/streamingcoord/client/assignment" "github.com/milvus-io/milvus/internal/streamingcoord/client/broadcast" @@ -16,13 +17,13 @@ import ( streamingserviceinterceptor "github.com/milvus-io/milvus/internal/util/streamingutil/service/interceptor" "github.com/milvus-io/milvus/internal/util/streamingutil/service/lazygrpc" "github.com/milvus-io/milvus/internal/util/streamingutil/service/resolver" - "github.com/milvus-io/milvus/internal/util/streamingutil/util" "github.com/milvus-io/milvus/pkg/v2/proto/streamingpb" "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" "github.com/milvus-io/milvus/pkg/v2/streaming/util/types" "github.com/milvus-io/milvus/pkg/v2/tracer" "github.com/milvus-io/milvus/pkg/v2/util/interceptor" "github.com/milvus-io/milvus/pkg/v2/util/paramtable" + "github.com/milvus-io/milvus/pkg/v2/util/replicateutil" "github.com/milvus-io/milvus/pkg/v2/util/typeutil" ) @@ -33,6 +34,12 @@ type AssignmentService interface { // AssignmentDiscover is used to watches the assignment discovery. types.AssignmentDiscoverWatcher + // UpdateReplicateConfiguration updates the replicate configuration to the milvus cluster. + UpdateReplicateConfiguration(ctx context.Context, config *commonpb.ReplicateConfiguration) error + + // GetReplicateConfiguration returns the replicate configuration of the milvus cluster. + GetReplicateConfiguration(ctx context.Context) (*replicateutil.ConfigHelper, error) + // GetLatestAssignments returns the latest assignment discovery result. GetLatestAssignments(ctx context.Context) (*types.VersionedStreamingNodeAssignments, error) @@ -89,7 +96,7 @@ func NewClient(etcdCli *clientv3.Client) Client { conn: conn, rb: rb, assignmentService: assignmentServiceImpl, - broadcastService: broadcast.NewGRPCBroadcastService(util.MustSelectWALName(), broadcastService), + broadcastService: broadcast.NewGRPCBroadcastService(broadcastService), } } diff --git a/internal/streamingcoord/server/balancer/balancer.go b/internal/streamingcoord/server/balancer/balancer.go index d6c75f49e6..000e6f6416 100644 --- a/internal/streamingcoord/server/balancer/balancer.go +++ b/internal/streamingcoord/server/balancer/balancer.go @@ -7,6 +7,7 @@ import ( "github.com/milvus-io/milvus/internal/streamingcoord/server/balancer/channel" "github.com/milvus-io/milvus/pkg/v2/proto/streamingpb" + "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" "github.com/milvus-io/milvus/pkg/v2/streaming/util/types" "github.com/milvus-io/milvus/pkg/v2/util/syncutil" ) @@ -26,6 +27,9 @@ type ( // Balancer is a local component, it should promise all channel can be assigned, and reach the final consistency. // Balancer should be thread safe. type Balancer interface { + // GetLatestChannelAssignment returns the latest channel assignment. + GetLatestChannelAssignment() (*WatchChannelAssignmentsCallbackParam, error) + // GetAllStreamingNodes fetches all streaming node info. GetAllStreamingNodes(ctx context.Context) (map[int64]*types.StreamingNodeInfo, error) @@ -51,6 +55,9 @@ type Balancer interface { // MarkAsAvailable marks the pchannels as available, and trigger a rebalance. MarkAsUnavailable(ctx context.Context, pChannels []types.PChannelInfo) error + // UpdateReplicateConfiguration updates the replicate configuration. + UpdateReplicateConfiguration(ctx context.Context, msgs ...message.ImmutablePutReplicateConfigMessageV2) error + // Trigger is a hint to trigger a balance. Trigger(ctx context.Context) error diff --git a/internal/streamingcoord/server/balancer/balancer_impl.go b/internal/streamingcoord/server/balancer/balancer_impl.go index e42172d066..2afe2ecda7 100644 --- a/internal/streamingcoord/server/balancer/balancer_impl.go +++ b/internal/streamingcoord/server/balancer/balancer_impl.go @@ -15,6 +15,7 @@ import ( "github.com/milvus-io/milvus/internal/util/streamingutil/service/resolver" "github.com/milvus-io/milvus/internal/util/streamingutil/status" "github.com/milvus-io/milvus/pkg/v2/log" + "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" "github.com/milvus-io/milvus/pkg/v2/streaming/util/types" "github.com/milvus-io/milvus/pkg/v2/util/contextutil" "github.com/milvus-io/milvus/pkg/v2/util/paramtable" @@ -83,6 +84,15 @@ func (b *balancerImpl) RegisterStreamingEnabledNotifier(notifier *syncutil.Async b.channelMetaManager.RegisterStreamingEnabledNotifier(notifier) } +func (b *balancerImpl) GetLatestChannelAssignment() (*WatchChannelAssignmentsCallbackParam, error) { + if !b.lifetime.Add(typeutil.LifetimeStateWorking) { + return nil, status.NewOnShutdownError("balancer is closing") + } + defer b.lifetime.Done() + + return b.channelMetaManager.GetLatestChannelAssignment() +} + // GetAllStreamingNodes fetches all streaming node info. func (b *balancerImpl) GetAllStreamingNodes(ctx context.Context) (map[int64]*types.StreamingNodeInfo, error) { return resource.Resource().StreamingNodeManagerClient().GetAllStreamingNodes(ctx) @@ -105,6 +115,22 @@ func (b *balancerImpl) WatchChannelAssignments(ctx context.Context, cb WatchChan return b.channelMetaManager.WatchAssignmentResult(ctx, cb) } +// UpdateReplicateConfiguration updates the replicate configuration. +func (b *balancerImpl) UpdateReplicateConfiguration(ctx context.Context, msgs ...message.ImmutablePutReplicateConfigMessageV2) error { + if !b.lifetime.Add(typeutil.LifetimeStateWorking) { + return status.NewOnShutdownError("balancer is closing") + } + defer b.lifetime.Done() + + ctx, cancel := contextutil.MergeContext(ctx, b.ctx) + defer cancel() + + if err := b.channelMetaManager.UpdateReplicateConfiguration(ctx, msgs...); err != nil { + return err + } + return nil +} + // UpdateBalancePolicy update the balance policy. func (b *balancerImpl) UpdateBalancePolicy(ctx context.Context, req *types.UpdateWALBalancePolicyRequest) (*types.UpdateWALBalancePolicyResponse, error) { if !b.lifetime.Add(typeutil.LifetimeStateWorking) { diff --git a/internal/streamingcoord/server/balancer/balancer_test.go b/internal/streamingcoord/server/balancer/balancer_test.go index 85f1667216..a67178dfc1 100644 --- a/internal/streamingcoord/server/balancer/balancer_test.go +++ b/internal/streamingcoord/server/balancer/balancer_test.go @@ -106,6 +106,7 @@ func TestBalancer(t *testing.T) { }, nil }) catalog.EXPECT().SavePChannels(mock.Anything, mock.Anything).Return(nil).Maybe() + catalog.EXPECT().GetReplicateConfiguration(mock.Anything).Return(nil, nil) // Test for lower datanode and proxy version protection. metaRoot := paramtable.Get().EtcdCfg.MetaRootPath.GetValue() @@ -331,6 +332,7 @@ func TestBalancer_WithRecoveryLag(t *testing.T) { }, nil }) catalog.EXPECT().SavePChannels(mock.Anything, mock.Anything).Return(nil).Maybe() + catalog.EXPECT().GetReplicateConfiguration(mock.Anything).Return(nil, nil) ctx := context.Background() b, err := balancer.RecoverBalancer(ctx, "test-channel-1") diff --git a/internal/streamingcoord/server/balancer/channel/manager.go b/internal/streamingcoord/server/balancer/channel/manager.go index b4eed38526..759dcf1ede 100644 --- a/internal/streamingcoord/server/balancer/channel/manager.go +++ b/internal/streamingcoord/server/balancer/channel/manager.go @@ -7,10 +7,14 @@ import ( "github.com/cockroachdb/errors" "google.golang.org/protobuf/proto" + "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" "github.com/milvus-io/milvus/internal/streamingcoord/server/resource" "github.com/milvus-io/milvus/pkg/v2/proto/streamingpb" + "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" "github.com/milvus-io/milvus/pkg/v2/streaming/util/types" + "github.com/milvus-io/milvus/pkg/v2/util/funcutil" "github.com/milvus-io/milvus/pkg/v2/util/paramtable" + "github.com/milvus-io/milvus/pkg/v2/util/replicateutil" "github.com/milvus-io/milvus/pkg/v2/util/retry" "github.com/milvus-io/milvus/pkg/v2/util/syncutil" "github.com/milvus-io/milvus/pkg/v2/util/typeutil" @@ -20,9 +24,11 @@ var ErrChannelNotExist = errors.New("channel not exist") type ( WatchChannelAssignmentsCallbackParam struct { - Version typeutil.VersionInt64Pair - CChannelAssignment *streamingpb.CChannelAssignment - Relations []types.PChannelInfoAssigned + Version typeutil.VersionInt64Pair + CChannelAssignment *streamingpb.CChannelAssignment + PChannelView *PChannelView + Relations []types.PChannelInfoAssigned + ReplicateConfiguration *commonpb.ReplicateConfiguration } WatchChannelAssignmentsCallback func(param WatchChannelAssignmentsCallbackParam) error ) @@ -39,7 +45,10 @@ func RecoverChannelManager(ctx context.Context, incomingChannel ...string) (*Cha if err != nil { return nil, err } - + replicateConfig, err := recoverReplicateConfiguration(ctx) + if err != nil { + return nil, err + } channels, metrics, err := recoverFromConfigurationAndMeta(ctx, streamingVersion, incomingChannel...) if err != nil { return nil, err @@ -56,6 +65,7 @@ func RecoverChannelManager(ctx context.Context, incomingChannel ...string) (*Cha metrics: metrics, cchannelMeta: cchannelMeta, streamingVersion: streamingVersion, + replicateConfig: replicateConfig, }, nil } @@ -116,6 +126,14 @@ func recoverFromConfigurationAndMeta(ctx context.Context, streamingVersion *stre return channels, metrics, nil } +func recoverReplicateConfiguration(ctx context.Context) (*replicateConfigHelper, error) { + config, err := resource.Resource().StreamingCatalog().GetReplicateConfiguration(ctx) + if err != nil { + return nil, err + } + return newReplicateConfigHelper(config), nil +} + // ChannelManager manages the channels. // ChannelManager is the `wal` of channel assignment and unassignment. // Every operation applied to the streaming node should be recorded in ChannelManager first. @@ -129,6 +147,7 @@ type ChannelManager struct { // null if no streaming service has been run. // 1 if streaming service has been run once. streamingEnableNotifiers []*syncutil.AsyncTaskNotifier[struct{}] + replicateConfig *replicateConfigHelper } // RegisterStreamingEnabledNotifier registers a notifier into the balancer. @@ -320,6 +339,18 @@ func (cm *ChannelManager) GetLatestWALLocated(ctx context.Context, pchannel stri return 0, false } +// GetLatestChannelAssignment returns the latest channel assignment. +func (cm *ChannelManager) GetLatestChannelAssignment() (*WatchChannelAssignmentsCallbackParam, error) { + var result WatchChannelAssignmentsCallbackParam + if _, err := cm.applyAssignments(func(param WatchChannelAssignmentsCallbackParam) error { + result = param + return nil + }); err != nil { + return nil, err + } + return &result, nil +} + func (cm *ChannelManager) WatchAssignmentResult(ctx context.Context, cb WatchChannelAssignmentsCallback) error { // push the first balance result to watcher callback function if balance result is ready. version, err := cm.applyAssignments(cb) @@ -337,6 +368,52 @@ func (cm *ChannelManager) WatchAssignmentResult(ctx context.Context, cb WatchCha } } +// UpdateReplicateConfiguration updates the in-memory replicate configuration. +func (cm *ChannelManager) UpdateReplicateConfiguration(ctx context.Context, msgs ...message.ImmutablePutReplicateConfigMessageV2) error { + config := replicateutil.MustNewConfigHelper(paramtable.Get().CommonCfg.ClusterPrefix.GetValue(), msgs[0].Header().ReplicateConfiguration) + pchannels := make([]types.AckedCheckpoint, 0, len(msgs)) + + for _, msg := range msgs { + pchannels = append(pchannels, types.AckedCheckpoint{ + Channel: funcutil.ToPhysicalChannel(msg.VChannel()), + MessageID: msg.LastConfirmedMessageID(), + LastConfirmedMessageID: msg.LastConfirmedMessageID(), + TimeTick: msg.TimeTick(), + }) + } + cm.cond.L.Lock() + defer cm.cond.L.Unlock() + + if cm.replicateConfig == nil { + cm.replicateConfig = newReplicateConfigHelperFromMessage(msgs[0]) + } else { + // StartUpdating starts the updating process. + if !cm.replicateConfig.StartUpdating(config.GetReplicateConfiguration(), msgs[0].BroadcastHeader().VChannels) { + return nil + } + } + cm.replicateConfig.Apply(config.GetReplicateConfiguration(), pchannels) + + dirtyConfig, dirtyCDCTasks, dirty := cm.replicateConfig.ConsumeIfDirty(config.GetReplicateConfiguration()) + if !dirty { + // the meta is not dirty, so nothing updated, return it directly. + return nil + } + if err := resource.Resource().StreamingCatalog().SaveReplicateConfiguration(ctx, dirtyConfig, dirtyCDCTasks); err != nil { + return err + } + + // If the acked result is nil, it means the all the channels are acked, + // so we can update the version and push the new replicate configuration into client. + if dirtyConfig.AckedResult == nil { + // update metrics. + cm.cond.UnsafeBroadcast() + cm.version.Local++ + cm.metrics.UpdateAssignmentVersion(cm.version.Local) + } + return nil +} + // applyAssignments applies the assignments. func (cm *ChannelManager) applyAssignments(cb WatchChannelAssignmentsCallback) (typeutil.VersionInt64Pair, error) { cm.cond.L.Lock() @@ -348,13 +425,21 @@ func (cm *ChannelManager) applyAssignments(cb WatchChannelAssignmentsCallback) ( } version := cm.version cchannelAssignment := proto.Clone(cm.cchannelMeta).(*streamingpb.CChannelMeta) + pchannelViews := newPChannelView(cm.channels) cm.cond.L.Unlock() + + var replicateConfig *commonpb.ReplicateConfiguration + if cm.replicateConfig != nil { + replicateConfig = cm.replicateConfig.GetReplicateConfiguration() + } return version, cb(WatchChannelAssignmentsCallbackParam{ Version: version, CChannelAssignment: &streamingpb.CChannelAssignment{ Meta: cchannelAssignment, }, - Relations: assignments, + PChannelView: pchannelViews, + Relations: assignments, + ReplicateConfiguration: replicateConfig, }) } diff --git a/internal/streamingcoord/server/balancer/channel/manager_test.go b/internal/streamingcoord/server/balancer/channel/manager_test.go index f4faab27fb..38c2aefb88 100644 --- a/internal/streamingcoord/server/balancer/channel/manager_test.go +++ b/internal/streamingcoord/server/balancer/channel/manager_test.go @@ -32,6 +32,7 @@ func TestChannelManager(t *testing.T) { Version: 1, }, nil) catalog.EXPECT().ListPChannel(mock.Anything).Return(nil, errors.New("recover failure")) + catalog.EXPECT().GetReplicateConfiguration(mock.Anything).Return(nil, nil) m, err := RecoverChannelManager(ctx) assert.Nil(t, m) assert.Error(t, err) @@ -131,6 +132,7 @@ func TestStreamingEnableChecker(t *testing.T) { catalog.EXPECT().GetVersion(mock.Anything).Return(nil, nil) catalog.EXPECT().SaveVersion(mock.Anything, mock.Anything).Return(nil) catalog.EXPECT().ListPChannel(mock.Anything).Return(nil, nil) + catalog.EXPECT().GetReplicateConfiguration(mock.Anything).Return(nil, nil) m, err := RecoverChannelManager(ctx, "test-channel") assert.NoError(t, err) @@ -183,6 +185,7 @@ func TestChannelManagerWatch(t *testing.T) { }, nil }) catalog.EXPECT().SavePChannels(mock.Anything, mock.Anything).Return(nil) + catalog.EXPECT().GetReplicateConfiguration(mock.Anything).Return(nil, nil) manager, err := RecoverChannelManager(context.Background()) assert.NoError(t, err) diff --git a/internal/streamingcoord/server/balancer/channel/pchannel_view.go b/internal/streamingcoord/server/balancer/channel/pchannel_view.go index 05108332e9..d143b5ef4a 100644 --- a/internal/streamingcoord/server/balancer/channel/pchannel_view.go +++ b/internal/streamingcoord/server/balancer/channel/pchannel_view.go @@ -22,7 +22,7 @@ func newPChannelView(metas map[ChannelID]*PChannelMeta) *PChannelView { panic(fmt.Sprintf("duplicate rw channel: %s", id.String())) } view.Channels[id] = meta - stat := StaticPChannelStatsManager.MustGet().GetPChannelStats(id).View() + stat := StaticPChannelStatsManager.Get().GetPChannelStats(id).View() stat.LastAssignTimestamp = meta.LastAssignTimestamp() view.Stats[id] = stat } diff --git a/internal/streamingcoord/server/balancer/channel/replicate_config.go b/internal/streamingcoord/server/balancer/channel/replicate_config.go new file mode 100644 index 0000000000..94a0e7a8bb --- /dev/null +++ b/internal/streamingcoord/server/balancer/channel/replicate_config.go @@ -0,0 +1,117 @@ +package channel + +import ( + "google.golang.org/protobuf/proto" + + "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" + "github.com/milvus-io/milvus/pkg/v2/proto/streamingpb" + "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" + "github.com/milvus-io/milvus/pkg/v2/streaming/util/types" + "github.com/milvus-io/milvus/pkg/v2/util/paramtable" + "github.com/milvus-io/milvus/pkg/v2/util/replicateutil" +) + +// replicateConfigHelper is a helper to manage the replicate configuration. +type replicateConfigHelper struct { + *replicateutil.ConfigHelper + ackedPendings *types.AckedResult + dirty bool +} + +// newReplicateConfigHelperFromMessage creates a new replicate config helper from message. +func newReplicateConfigHelperFromMessage(replicateConfig message.ImmutablePutReplicateConfigMessageV2) *replicateConfigHelper { + return newReplicateConfigHelper(&streamingpb.ReplicateConfigurationMeta{ + ReplicateConfiguration: nil, + AckedResult: types.NewAckedPendings(replicateConfig.BroadcastHeader().VChannels).AckedResult, + }) +} + +// newReplicateConfigHelper creates a new replicate config helper from proto. +func newReplicateConfigHelper(replicateConfig *streamingpb.ReplicateConfigurationMeta) *replicateConfigHelper { + if replicateConfig == nil { + return nil + } + return &replicateConfigHelper{ + ConfigHelper: replicateutil.MustNewConfigHelper(paramtable.Get().CommonCfg.ClusterPrefix.GetValue(), replicateConfig.GetReplicateConfiguration()), + ackedPendings: types.NewAckedPendingsFromProto(replicateConfig.GetAckedResult()), + dirty: false, + } +} + +// StartUpdating starts the updating process. +// return true if the replicate configuration is changed, false otherwise. +func (rc *replicateConfigHelper) StartUpdating(config *commonpb.ReplicateConfiguration, pchannels []string) bool { + if rc.ConfigHelper != nil && proto.Equal(config, rc.GetReplicateConfiguration()) { + return false + } + if rc.ackedPendings == nil { + rc.ackedPendings = types.NewAckedPendings(pchannels) + } + return true +} + +// Apply applies the replicate configuration to the wal. +func (rc *replicateConfigHelper) Apply(config *commonpb.ReplicateConfiguration, cp []types.AckedCheckpoint) { + if rc.ackedPendings == nil { + panic("ackedPendings is nil when applying replicate configuration") + } + for _, cp := range cp { + if rc.ackedPendings.Ack(cp) { + rc.dirty = true + } + } +} + +// ConsumeIfDirty consumes the dirty part of the replicate configuration. +func (rc *replicateConfigHelper) ConsumeIfDirty(incoming *commonpb.ReplicateConfiguration) (config *streamingpb.ReplicateConfigurationMeta, replicatingTasks []*streamingpb.ReplicatePChannelMeta, dirty bool) { + if !rc.dirty { + return nil, nil, false + } + rc.dirty = false + + if !rc.ackedPendings.IsAllAcked() { + // not all the channels are acked, return the current replicate configuration and acked result. + var cfg *commonpb.ReplicateConfiguration + if rc.ConfigHelper != nil { + cfg = rc.ConfigHelper.GetReplicateConfiguration() + } + return &streamingpb.ReplicateConfigurationMeta{ + ReplicateConfiguration: cfg, + AckedResult: rc.ackedPendings.AckedResult, + }, nil, true + } + + // all the channels are acked, return the new replicate configuration and acked result. + newConfig := replicateutil.MustNewConfigHelper(paramtable.Get().CommonCfg.ClusterPrefix.GetValue(), incoming) + newIncomingCDCTasks := rc.getNewIncomingTask(newConfig) + rc.ConfigHelper = newConfig + rc.ackedPendings = nil + return &streamingpb.ReplicateConfigurationMeta{ + ReplicateConfiguration: incoming, + AckedResult: nil, + }, newIncomingCDCTasks, true +} + +// getNewIncomingTask gets the new incoming task from replicatingTasks. +func (cm *replicateConfigHelper) getNewIncomingTask(newConfig *replicateutil.ConfigHelper) []*streamingpb.ReplicatePChannelMeta { + incoming := newConfig.GetCurrentCluster() + var current *replicateutil.MilvusCluster + if cm.ConfigHelper != nil { + current = cm.ConfigHelper.GetCurrentCluster() + } + incomingReplicatingTasks := make([]*streamingpb.ReplicatePChannelMeta, 0, len(incoming.TargetClusters())) + for _, targetCluster := range incoming.TargetClusters() { + if current != nil && current.TargetCluster(targetCluster.GetClusterId()) != nil { + // target already exists, skip it. + continue + } + for _, pchannel := range targetCluster.GetPchannels() { + incomingReplicatingTasks = append(incomingReplicatingTasks, &streamingpb.ReplicatePChannelMeta{ + SourceChannelName: targetCluster.MustGetSourceChannel(pchannel), + TargetChannelName: pchannel, + TargetCluster: targetCluster.MilvusCluster, + }) + } + } + return incomingReplicatingTasks +} diff --git a/internal/streamingcoord/server/balancer/channel/replicate_config_test.go b/internal/streamingcoord/server/balancer/channel/replicate_config_test.go new file mode 100644 index 0000000000..45bbbeee3b --- /dev/null +++ b/internal/streamingcoord/server/balancer/channel/replicate_config_test.go @@ -0,0 +1,129 @@ +package channel + +import ( + "testing" + + "github.com/stretchr/testify/suite" + + "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" + "github.com/milvus-io/milvus/pkg/v2/proto/streamingpb" + "github.com/milvus-io/milvus/pkg/v2/streaming/util/types" + "github.com/milvus-io/milvus/pkg/v2/streaming/walimpls/impls/walimplstest" +) + +type ReplicateConfigHelperSuite struct { + suite.Suite + helper *replicateConfigHelper +} + +func TestReplicateConfigHelperSuite(t *testing.T) { + suite.Run(t, new(ReplicateConfigHelperSuite)) +} + +func (s *ReplicateConfigHelperSuite) SetupTest() { + s.helper = nil +} + +func (s *ReplicateConfigHelperSuite) TestNewReplicateConfigHelper() { + // Test nil input + helper := newReplicateConfigHelper(nil) + s.Nil(helper) + + // Test valid input + meta := &streamingpb.ReplicateConfigurationMeta{ + ReplicateConfiguration: &commonpb.ReplicateConfiguration{ + Clusters: []*commonpb.MilvusCluster{ + {ClusterId: "by-dev"}, + }, + }, + AckedResult: types.NewAckedPendings([]string{"p1", "p2"}).AckedResult, + } + helper = newReplicateConfigHelper(meta) + s.NotNil(helper) + s.NotNil(helper.ConfigHelper) + s.NotNil(helper.ackedPendings) + s.False(helper.dirty) +} + +func (s *ReplicateConfigHelperSuite) TestStartUpdating() { + s.helper = &replicateConfigHelper{ + ConfigHelper: nil, + ackedPendings: nil, + dirty: false, + } + + config := &commonpb.ReplicateConfiguration{ + Clusters: []*commonpb.MilvusCluster{ + {ClusterId: "by-dev"}, + }, + } + pchannels := []string{"p1", "p2"} + + // First update should return true + changed := s.helper.StartUpdating(config, pchannels) + s.True(changed) + s.NotNil(s.helper.ackedPendings) + + s.helper.Apply(config, []types.AckedCheckpoint{ + {Channel: "p1", MessageID: walimplstest.NewTestMessageID(1), LastConfirmedMessageID: walimplstest.NewTestMessageID(1), TimeTick: 1}, + {Channel: "p2", MessageID: walimplstest.NewTestMessageID(1), LastConfirmedMessageID: walimplstest.NewTestMessageID(1), TimeTick: 1}, + }) + s.helper.ConsumeIfDirty(config) + + // Same config should return false + changed = s.helper.StartUpdating(config, pchannels) + s.False(changed) +} + +func (s *ReplicateConfigHelperSuite) TestApply() { + s.helper = &replicateConfigHelper{ + ConfigHelper: nil, + ackedPendings: types.NewAckedPendings([]string{"p1", "p2"}), + dirty: false, + } + + config := &commonpb.ReplicateConfiguration{} + checkpoints := []types.AckedCheckpoint{ + {Channel: "p1", MessageID: walimplstest.NewTestMessageID(1), LastConfirmedMessageID: walimplstest.NewTestMessageID(1), TimeTick: 1}, + {Channel: "p2", MessageID: walimplstest.NewTestMessageID(1), LastConfirmedMessageID: walimplstest.NewTestMessageID(1), TimeTick: 1}, + } + + s.helper.Apply(config, checkpoints) + s.True(s.helper.dirty) + s.True(s.helper.ackedPendings.IsAllAcked()) +} + +func (s *ReplicateConfigHelperSuite) TestConsumeIfDirty() { + s.helper = &replicateConfigHelper{ + ConfigHelper: nil, + ackedPendings: types.NewAckedPendings([]string{"p1", "p2"}), + dirty: true, + } + + // Not all acked case + config, tasks, dirty := s.helper.ConsumeIfDirty(&commonpb.ReplicateConfiguration{ + Clusters: []*commonpb.MilvusCluster{ + {ClusterId: "by-dev"}, + }, + }) + s.NotNil(config) + s.Nil(tasks) + s.True(dirty) + s.False(s.helper.dirty) + + // All acked case + s.helper.dirty = true + s.helper.ackedPendings.Ack(types.AckedCheckpoint{Channel: "p1", MessageID: walimplstest.NewTestMessageID(1), LastConfirmedMessageID: walimplstest.NewTestMessageID(1), TimeTick: 1}) + s.helper.ackedPendings.Ack(types.AckedCheckpoint{Channel: "p2", MessageID: walimplstest.NewTestMessageID(1), LastConfirmedMessageID: walimplstest.NewTestMessageID(1), TimeTick: 1}) + + config, tasks, dirty = s.helper.ConsumeIfDirty(&commonpb.ReplicateConfiguration{ + Clusters: []*commonpb.MilvusCluster{ + {ClusterId: "by-dev"}, + }, + }) + s.NotNil(config) + s.NotNil(tasks) + s.True(dirty) + s.False(s.helper.dirty) + s.Nil(s.helper.ackedPendings) +} diff --git a/internal/streamingcoord/server/service/assignment.go b/internal/streamingcoord/server/service/assignment.go index 91814ec82c..6b124b7fb3 100644 --- a/internal/streamingcoord/server/service/assignment.go +++ b/internal/streamingcoord/server/service/assignment.go @@ -4,12 +4,20 @@ import ( "context" "github.com/prometheus/client_golang/prometheus" + "github.com/samber/lo" + "go.uber.org/zap" + "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" "github.com/milvus-io/milvus/internal/streamingcoord/server/balancer" + "github.com/milvus-io/milvus/internal/streamingcoord/server/balancer/channel" "github.com/milvus-io/milvus/internal/streamingcoord/server/service/discover" + "github.com/milvus-io/milvus/pkg/v2/log" "github.com/milvus-io/milvus/pkg/v2/metrics" "github.com/milvus-io/milvus/pkg/v2/proto/streamingpb" + "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" + "github.com/milvus-io/milvus/pkg/v2/streaming/walimpls/impls/rmq" "github.com/milvus-io/milvus/pkg/v2/util/paramtable" + "github.com/milvus-io/milvus/pkg/v2/util/replicateutil" "github.com/milvus-io/milvus/pkg/v2/util/syncutil" ) @@ -19,10 +27,13 @@ var _ streamingpb.StreamingCoordAssignmentServiceServer = (*assignmentServiceImp func NewAssignmentService( balancer *syncutil.Future[balancer.Balancer], ) streamingpb.StreamingCoordAssignmentServiceServer { - return &assignmentServiceImpl{ + assignmentService := &assignmentServiceImpl{ balancer: balancer, listenerTotal: metrics.StreamingCoordAssignmentListenerTotal.WithLabelValues(paramtable.GetStringNodeID()), } + // TODO: after recovering from wal, add it to here. + // registry.RegisterPutReplicateConfigV2AckCallback(assignmentService.putReplicateConfiguration) + return assignmentService } type AssignmentService interface { @@ -31,6 +42,8 @@ type AssignmentService interface { // assignmentServiceImpl is the implementation of the assignment service. type assignmentServiceImpl struct { + streamingpb.UnimplementedStreamingCoordAssignmentServiceServer + balancer *syncutil.Future[balancer.Balancer] listenerTotal prometheus.Gauge } @@ -47,6 +60,86 @@ func (s *assignmentServiceImpl) AssignmentDiscover(server streamingpb.StreamingC return discover.NewAssignmentDiscoverServer(balancer, server).Execute() } +// UpdateReplicateConfiguration updates the replicate configuration to the milvus cluster. +func (s *assignmentServiceImpl) UpdateReplicateConfiguration(ctx context.Context, req *streamingpb.UpdateReplicateConfigurationRequest) (*streamingpb.UpdateReplicateConfigurationResponse, error) { + config := req.GetConfiguration() + + log.Ctx(ctx).Info("UpdateReplicateConfiguration received", replicateutil.ConfigLogFields(config)...) + + // TODO: after recovering from wal, do a broadcast operation here. + msg, err := s.validateReplicateConfiguration(ctx, config) + if err != nil { + return nil, err + } + + // TODO: After recovering from wal, we can get the immutable message from wal system. + // Now, we just mock the immutable message here. + mutableMsg := msg.SplitIntoMutableMessage() + mockMessages := make([]message.ImmutablePutReplicateConfigMessageV2, 0) + for _, msg := range mutableMsg { + mockMessages = append(mockMessages, + message.MustAsImmutablePutReplicateConfigMessageV2(msg.WithTimeTick(0).WithLastConfirmedUseMessageID().IntoImmutableMessage(rmq.NewRmqID(1))), + ) + } + + // TODO: After recovering from wal, remove the operation here. + if err := s.putReplicateConfiguration(ctx, mockMessages...); err != nil { + return nil, err + } + return &streamingpb.UpdateReplicateConfigurationResponse{}, nil +} + +// validateReplicateConfiguration validates the replicate configuration. +func (s *assignmentServiceImpl) validateReplicateConfiguration(ctx context.Context, config *commonpb.ReplicateConfiguration) (message.BroadcastMutableMessage, error) { + balancer, err := s.balancer.GetWithContext(ctx) + if err != nil { + return nil, err + } + + // get all pchannels + latestAssignment, err := balancer.GetLatestChannelAssignment() + if err != nil { + return nil, err + } + pchannels := lo.MapToSlice(latestAssignment.PChannelView.Channels, func(_ channel.ChannelID, channel *channel.PChannelMeta) string { + return channel.Name() + }) + + // validate the configuration itself + currentClusterID := paramtable.Get().CommonCfg.ClusterPrefix.GetValue() + validator := replicateutil.NewReplicateConfigValidator(config, currentClusterID, pchannels) + if err := validator.Validate(); err != nil { + log.Ctx(ctx).Warn("UpdateReplicateConfiguration fail", zap.Error(err)) + return nil, err + } + + // TODO: validate the incoming configuration is compatible with the current config. + if _, err := replicateutil.NewConfigHelper(paramtable.Get().CommonCfg.ClusterPrefix.GetValue(), config); err != nil { + return nil, err + } + b := message.NewPutReplicateConfigMessageBuilderV2(). + WithHeader(&message.PutReplicateConfigMessageHeader{ + ReplicateConfiguration: config, + }). + WithBody(&message.PutReplicateConfigMessageBody{}). + WithBroadcast(pchannels). + MustBuildBroadcast() + + // TODO: After recovering from wal, remove the operation here. + b.WithBroadcastID(1) + return b, nil +} + +// putReplicateConfiguration puts the replicate configuration into the balancer. +// It's a callback function of the broadcast service. +func (s *assignmentServiceImpl) putReplicateConfiguration(ctx context.Context, msgs ...message.ImmutablePutReplicateConfigMessageV2) error { + balancer, err := s.balancer.GetWithContext(ctx) + if err != nil { + return err + } + return balancer.UpdateReplicateConfiguration(ctx, msgs...) +} + // UpdateWALBalancePolicy is used to update the WAL balance policy. func (s *assignmentServiceImpl) UpdateWALBalancePolicy(ctx context.Context, req *streamingpb.UpdateWALBalancePolicyRequest) (*streamingpb.UpdateWALBalancePolicyResponse, error) { balancer, err := s.balancer.GetWithContext(ctx) diff --git a/internal/streamingcoord/server/service/broadcast.go b/internal/streamingcoord/server/service/broadcast.go index c1534b170f..f552692a66 100644 --- a/internal/streamingcoord/server/service/broadcast.go +++ b/internal/streamingcoord/server/service/broadcast.go @@ -4,7 +4,6 @@ import ( "context" "github.com/milvus-io/milvus/internal/streamingcoord/server/broadcaster" - "github.com/milvus-io/milvus/internal/util/streamingutil/util" "github.com/milvus-io/milvus/pkg/v2/proto/streamingpb" "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" "github.com/milvus-io/milvus/pkg/v2/util/syncutil" @@ -19,14 +18,12 @@ type BroadcastService interface { func NewBroadcastService(bc *syncutil.Future[broadcaster.Broadcaster]) BroadcastService { return &broadcastServceImpl{ broadcaster: bc, - walName: util.MustSelectWALName(), } } // broadcastServiceeeeImpl is the implementation of the broadcast service. type broadcastServceImpl struct { broadcaster *syncutil.Future[broadcaster.Broadcaster] - walName string } // Broadcast broadcasts the message to all channels. @@ -63,7 +60,11 @@ func (s *broadcastServceImpl) Ack(ctx context.Context, req *streamingpb.Broadcas } return &streamingpb.BroadcastAckResponse{}, nil } - if err := broadcaster.Ack(ctx, message.NewImmutableMessageFromProto(s.walName, req.Message)); err != nil { + if err := broadcaster.Ack(ctx, message.NewImmutableMesasge( + message.MustUnmarshalMessageID(req.Message.Id), + req.Message.Payload, + req.Message.Properties, + )); err != nil { return nil, err } return &streamingpb.BroadcastAckResponse{}, nil diff --git a/internal/streamingcoord/server/service/broadcast_test.go b/internal/streamingcoord/server/service/broadcast_test.go new file mode 100644 index 0000000000..407172880b --- /dev/null +++ b/internal/streamingcoord/server/service/broadcast_test.go @@ -0,0 +1,46 @@ +package service + +import ( + "context" + "testing" + + "github.com/stretchr/testify/mock" + + "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" + "github.com/milvus-io/milvus/internal/mocks/streamingcoord/server/mock_broadcaster" + "github.com/milvus-io/milvus/internal/streamingcoord/server/broadcaster" + "github.com/milvus-io/milvus/pkg/v2/proto/messagespb" + "github.com/milvus-io/milvus/pkg/v2/proto/streamingpb" + "github.com/milvus-io/milvus/pkg/v2/streaming/util/types" + "github.com/milvus-io/milvus/pkg/v2/streaming/walimpls/impls/walimplstest" + "github.com/milvus-io/milvus/pkg/v2/util/syncutil" +) + +func TestBroadcastService(t *testing.T) { + fb := syncutil.NewFuture[broadcaster.Broadcaster]() + mb := mock_broadcaster.NewMockBroadcaster(t) + fb.Set(mb) + mb.EXPECT().Broadcast(mock.Anything, mock.Anything).Return(&types.BroadcastAppendResult{}, nil) + mb.EXPECT().Ack(mock.Anything, mock.Anything).Return(nil) + mb.EXPECT().LegacyAck(mock.Anything, mock.Anything, mock.Anything).Return(nil) + service := NewBroadcastService(fb) + service.Broadcast(context.Background(), &streamingpb.BroadcastRequest{ + Message: &messagespb.Message{ + Payload: []byte("payload"), + Properties: map[string]string{"_bh": "1"}, + }, + }) + service.Ack(context.Background(), &streamingpb.BroadcastAckRequest{ + BroadcastId: 1, + Vchannel: "v1", + }) + service.Ack(context.Background(), &streamingpb.BroadcastAckRequest{ + BroadcastId: 1, + Vchannel: "v1", + Message: &commonpb.ImmutableMessage{ + Id: walimplstest.NewTestMessageID(1).IntoProto(), + Payload: []byte("payload"), + Properties: map[string]string{"key": "value"}, + }, + }) +} diff --git a/internal/streamingcoord/server/service/discover/discover_grpc_server_helper.go b/internal/streamingcoord/server/service/discover/discover_grpc_server_helper.go index 2ed6521b49..6f5ad4bfb1 100644 --- a/internal/streamingcoord/server/service/discover/discover_grpc_server_helper.go +++ b/internal/streamingcoord/server/service/discover/discover_grpc_server_helper.go @@ -36,8 +36,9 @@ func (h *discoverGrpcServerHelper) SendFullAssignment(param balancer.WatchChanne Global: param.Version.Global, Local: param.Version.Local, }, - Assignments: assignments, - Cchannel: param.CChannelAssignment, + Assignments: assignments, + Cchannel: param.CChannelAssignment, + ReplicateConfiguration: param.ReplicateConfiguration, }, }, }) diff --git a/internal/streamingcoord/server/service_test.go b/internal/streamingcoord/server/service_test.go index b0296e9db9..efe7e35d6b 100644 --- a/internal/streamingcoord/server/service_test.go +++ b/internal/streamingcoord/server/service_test.go @@ -8,6 +8,7 @@ import ( "github.com/stretchr/testify/assert" etcdkv "github.com/milvus-io/milvus/internal/kv/etcd" + "github.com/milvus-io/milvus/internal/streamingcoord/server/balancer/channel" "github.com/milvus-io/milvus/internal/types" "github.com/milvus-io/milvus/internal/util/sessionutil" "github.com/milvus-io/milvus/pkg/v2/util/etcd" @@ -20,6 +21,8 @@ func TestServer(t *testing.T) { params := paramtable.Get() + channel.RecoverPChannelStatsManager([]string{}) + endpoints := params.EtcdCfg.Endpoints.GetValue() etcdEndpoints := strings.Split(endpoints, ",") c, err := etcd.GetRemoteEtcdClient(etcdEndpoints) diff --git a/internal/streamingnode/client/handler/consumer/consumer_impl.go b/internal/streamingnode/client/handler/consumer/consumer_impl.go index 55d3befe32..bc9d76b9db 100644 --- a/internal/streamingnode/client/handler/consumer/consumer_impl.go +++ b/internal/streamingnode/client/handler/consumer/consumer_impl.go @@ -172,7 +172,7 @@ func (c *consumerImpl) recvLoop() (err error) { } switch resp := resp.Response.(type) { case *streamingpb.ConsumeResponse_Consume: - msgID, err := message.UnmarshalMessageID(c.walName, resp.Consume.GetMessage().GetId().GetId()) + msgID, err := message.UnmarshalMessageID(resp.Consume.Message.Id) if err != nil { return err } diff --git a/internal/streamingnode/client/handler/consumer/consumer_test.go b/internal/streamingnode/client/handler/consumer/consumer_test.go index 2a2a4b4a93..6a656a12fc 100644 --- a/internal/streamingnode/client/handler/consumer/consumer_test.go +++ b/internal/streamingnode/client/handler/consumer/consumer_test.go @@ -153,9 +153,7 @@ func newMockedConsumerImpl(t *testing.T, ctx context.Context, h message.Handler) recvCh <- &streamingpb.ConsumeResponse{ Response: &streamingpb.ConsumeResponse_Create{ - Create: &streamingpb.CreateConsumerResponse{ - WalName: walimplstest.WALName, - }, + Create: &streamingpb.CreateConsumerResponse{}, }, } recvCh <- &streamingpb.ConsumeResponse{ diff --git a/internal/streamingnode/client/handler/handler_client.go b/internal/streamingnode/client/handler/handler_client.go index de6fbc8847..bf67581d81 100644 --- a/internal/streamingnode/client/handler/handler_client.go +++ b/internal/streamingnode/client/handler/handler_client.go @@ -12,6 +12,7 @@ import ( "github.com/milvus-io/milvus/internal/streamingnode/client/handler/assignment" "github.com/milvus-io/milvus/internal/streamingnode/client/handler/consumer" "github.com/milvus-io/milvus/internal/streamingnode/client/handler/producer" + "github.com/milvus-io/milvus/internal/streamingnode/server/wal" "github.com/milvus-io/milvus/internal/util/streamingutil/service/balancer/picker" streamingserviceinterceptor "github.com/milvus-io/milvus/internal/util/streamingutil/service/interceptor" "github.com/milvus-io/milvus/internal/util/streamingutil/service/lazygrpc" @@ -70,6 +71,9 @@ type HandlerClient interface { // If the wal is located at remote, it will return 0, error. GetLatestMVCCTimestampIfLocal(ctx context.Context, vchannel string) (uint64, error) + // GetReplicateCheckpoint returns the WAL checkpoint that will be used to create scanner. + GetReplicateCheckpoint(ctx context.Context, channelName string) (*wal.ReplicateCheckpoint, error) + // GetWALMetricsIfLocal gets the metrics of the local wal. // It will only return the metrics of the local wal but not the remote wal. GetWALMetricsIfLocal(ctx context.Context) (*types.StreamingNodeMetrics, error) diff --git a/internal/streamingnode/client/handler/handler_client_impl.go b/internal/streamingnode/client/handler/handler_client_impl.go index 2f229c7fc6..ed031648d5 100644 --- a/internal/streamingnode/client/handler/handler_client_impl.go +++ b/internal/streamingnode/client/handler/handler_client_impl.go @@ -65,6 +65,18 @@ func (hc *handlerClientImpl) GetLatestMVCCTimestampIfLocal(ctx context.Context, return w.GetLatestMVCCTimestamp(ctx, vchannel) } +// GetReplicateCheckpoint returns the WAL checkpoint that will be used to create scanner. +func (hc *handlerClientImpl) GetReplicateCheckpoint(ctx context.Context, channelName string) (*wal.ReplicateCheckpoint, error) { + if !hc.lifetime.Add(typeutil.LifetimeStateWorking) { + return nil, ErrClientClosed + } + defer hc.lifetime.Done() + + return nil, nil + + // TODO: sheep, implement it. +} + // GetWALMetricsIfLocal gets the metrics of the local wal. func (hc *handlerClientImpl) GetWALMetricsIfLocal(ctx context.Context) (*types.StreamingNodeMetrics, error) { if !hc.lifetime.Add(typeutil.LifetimeStateWorking) { diff --git a/internal/streamingnode/client/handler/producer/producer_impl.go b/internal/streamingnode/client/handler/producer/producer_impl.go index 3659096c72..cb64a9bbf4 100644 --- a/internal/streamingnode/client/handler/producer/producer_impl.go +++ b/internal/streamingnode/client/handler/producer/producer_impl.go @@ -298,10 +298,7 @@ func (p *producerImpl) recvLoop() (err error) { var result produceResponse switch produceResp := resp.Produce.Response.(type) { case *streamingpb.ProduceMessageResponse_Result: - msgID, err := message.UnmarshalMessageID( - p.walName, - produceResp.Result.GetId().GetId(), - ) + msgID, err := message.UnmarshalMessageID(produceResp.Result.GetId()) if err != nil { return err } diff --git a/internal/streamingnode/client/handler/producer/producer_test.go b/internal/streamingnode/client/handler/producer/producer_test.go index 5f0c10d9b5..9867d4e8f6 100644 --- a/internal/streamingnode/client/handler/producer/producer_test.go +++ b/internal/streamingnode/client/handler/producer/producer_test.go @@ -10,7 +10,6 @@ import ( "github.com/stretchr/testify/mock" "github.com/milvus-io/milvus/pkg/v2/mocks/proto/mock_streamingpb" - "github.com/milvus-io/milvus/pkg/v2/proto/messagespb" "github.com/milvus-io/milvus/pkg/v2/proto/streamingpb" "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" "github.com/milvus-io/milvus/pkg/v2/streaming/util/types" @@ -50,9 +49,7 @@ func TestProducer(t *testing.T) { recvCh <- &streamingpb.ProduceResponse{ Response: &streamingpb.ProduceResponse_Create{ - Create: &streamingpb.CreateProducerResponse{ - WalName: walimplstest.WALName, - }, + Create: &streamingpb.CreateProducerResponse{}, }, } producer, err := CreateProducer(ctx, opts, c) @@ -89,7 +86,7 @@ func TestProducer(t *testing.T) { RequestId: 2, Response: &streamingpb.ProduceMessageResponse_Result{ Result: &streamingpb.ProduceMessageResponseResult{ - Id: &messagespb.MessageID{Id: walimplstest.NewTestMessageID(1).Marshal()}, + Id: walimplstest.NewTestMessageID(1).IntoProto(), }, }, }, diff --git a/internal/streamingnode/server/flusher/flusherimpl/util.go b/internal/streamingnode/server/flusher/flusherimpl/util.go index ea4bd2ccef..cc5fe67091 100644 --- a/internal/streamingnode/server/flusher/flusherimpl/util.go +++ b/internal/streamingnode/server/flusher/flusherimpl/util.go @@ -44,7 +44,7 @@ func (impl *WALFlusherImpl) getRecoveryInfos(ctx context.Context, vchannel []str var checkpoint message.MessageID for _, info := range recoveryInfos { - messageID := adaptor.MustGetMessageIDFromMQWrapperIDBytes(impl.wal.Get().WALName(), info.GetInfo().GetSeekPosition().GetMsgID()) + messageID := adaptor.MustGetMessageIDFromMQWrapperIDBytes(info.GetInfo().GetSeekPosition().GetMsgID()) if checkpoint == nil || messageID.LT(checkpoint) { checkpoint = messageID } diff --git a/internal/streamingnode/server/flusher/flusherimpl/wal_flusher.go b/internal/streamingnode/server/flusher/flusherimpl/wal_flusher.go index 680d75ac35..7cd78b9c7f 100644 --- a/internal/streamingnode/server/flusher/flusherimpl/wal_flusher.go +++ b/internal/streamingnode/server/flusher/flusherimpl/wal_flusher.go @@ -156,7 +156,7 @@ func (impl *WALFlusherImpl) buildFlusherComponents(ctx context.Context, l wal.WA chunkManager := resource.Resource().ChunkManager() cpUpdater := util.NewChannelCheckpointUpdaterWithCallback(broker, func(mp *msgpb.MsgPosition) { - messageID := adaptor.MustGetMessageIDFromMQWrapperIDBytes(l.WALName(), mp.MsgID) + messageID := adaptor.MustGetMessageIDFromMQWrapperIDBytes(mp.MsgID) impl.RecoveryStorage.UpdateFlusherCheckpoint(mp.ChannelName, &recovery.WALCheckpoint{ MessageID: messageID, TimeTick: mp.Timestamp, diff --git a/internal/streamingnode/server/flusher/flusherimpl/wal_flusher_test.go b/internal/streamingnode/server/flusher/flusherimpl/wal_flusher_test.go index f6aa228a5b..c8d194ee81 100644 --- a/internal/streamingnode/server/flusher/flusherimpl/wal_flusher_test.go +++ b/internal/streamingnode/server/flusher/flusherimpl/wal_flusher_test.go @@ -21,6 +21,7 @@ import ( "github.com/milvus-io/milvus/internal/streamingnode/server/wal/recovery" internaltypes "github.com/milvus-io/milvus/internal/types" "github.com/milvus-io/milvus/internal/util/streamingutil" + "github.com/milvus-io/milvus/internal/util/streamingutil/util" "github.com/milvus-io/milvus/pkg/v2/common" "github.com/milvus-io/milvus/pkg/v2/proto/datapb" "github.com/milvus-io/milvus/pkg/v2/proto/streamingpb" @@ -30,12 +31,16 @@ import ( "github.com/milvus-io/milvus/pkg/v2/util/merr" "github.com/milvus-io/milvus/pkg/v2/util/paramtable" "github.com/milvus-io/milvus/pkg/v2/util/syncutil" + "github.com/milvus-io/milvus/pkg/v2/util/typeutil" ) func TestMain(m *testing.M) { defaultCollectionNotFoundTolerance = 2 paramtable.Init() + paramtable.SetRole(typeutil.StandaloneRole) + paramtable.Get().MQCfg.Type.SwapTempValue(message.WALNameRocksmq.String()) + util.InitAndSelectWALName() if code := m.Run(); code != 0 { os.Exit(code) } @@ -143,10 +148,7 @@ func newMockMixcoord(t *testing.T, maybe bool) *mocks.MockMixCoordClient { func newMockWAL(t *testing.T, maybe bool) *mock_wal.MockWAL { w := mock_wal.NewMockWAL(t) - walName := w.EXPECT().WALName().Return("rocksmq") - if maybe { - walName.Maybe() - } + w.EXPECT().WALName().Return(message.WALNameRocksmq).Maybe() w.EXPECT().Channel().Return(types.PChannelInfo{Name: "pchannel"}).Maybe() read := w.EXPECT().Read(mock.Anything, mock.Anything).RunAndReturn( func(ctx context.Context, option wal.ReadOption) (wal.Scanner, error) { diff --git a/internal/streamingnode/server/server.go b/internal/streamingnode/server/server.go index fcdfad7029..1371f7f826 100644 --- a/internal/streamingnode/server/server.go +++ b/internal/streamingnode/server/server.go @@ -9,12 +9,10 @@ import ( "github.com/milvus-io/milvus/internal/streamingnode/server/resource" "github.com/milvus-io/milvus/internal/streamingnode/server/service" "github.com/milvus-io/milvus/internal/streamingnode/server/walmanager" - "github.com/milvus-io/milvus/internal/util/hookutil" "github.com/milvus-io/milvus/internal/util/initcore" "github.com/milvus-io/milvus/internal/util/sessionutil" "github.com/milvus-io/milvus/pkg/v2/log" "github.com/milvus-io/milvus/pkg/v2/proto/streamingpb" - "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" _ "github.com/milvus-io/milvus/pkg/v2/streaming/walimpls/impls/kafka" _ "github.com/milvus-io/milvus/pkg/v2/streaming/walimpls/impls/pulsar" _ "github.com/milvus-io/milvus/pkg/v2/streaming/walimpls/impls/rmq" @@ -54,9 +52,6 @@ func (s *Server) init() { // init paramtable change callback for core related config initcore.SetupCoreConfigChangelCallback() - if hookutil.IsClusterEncyptionEnabled() { - message.RegisterCipher(hookutil.GetCipher()) - } } // Stop stops the streamingnode server. diff --git a/internal/streamingnode/server/service/handler.go b/internal/streamingnode/server/service/handler.go index 82051d4fc3..53e3626e43 100644 --- a/internal/streamingnode/server/service/handler.go +++ b/internal/streamingnode/server/service/handler.go @@ -1,6 +1,8 @@ package service import ( + "context" + "github.com/milvus-io/milvus/internal/streamingnode/server/service/handler/consumer" "github.com/milvus-io/milvus/internal/streamingnode/server/service/handler/producer" "github.com/milvus-io/milvus/internal/streamingnode/server/walmanager" @@ -28,6 +30,11 @@ type handlerServiceImpl struct { walManager walmanager.Manager } +// GetReplicateCheckpoint returns the WAL checkpoint that will be used to create scanner +func (hs *handlerServiceImpl) GetReplicateCheckpoint(ctx context.Context, req *streamingpb.GetReplicateCheckpointRequest) (*streamingpb.GetReplicateCheckpointResponse, error) { + panic("not implemented") // TODO: sheep, implement it. +} + // Produce creates a new producer for the channel on this log node. func (hs *handlerServiceImpl) Produce(streamServer streamingpb.StreamingNodeHandlerService_ProduceServer) error { p, err := producer.CreateProduceServer(hs.walManager, streamServer) diff --git a/internal/streamingnode/server/service/handler/consumer/consume_server.go b/internal/streamingnode/server/service/handler/consumer/consume_server.go index 8584f29e93..21dc1aa35e 100644 --- a/internal/streamingnode/server/service/handler/consumer/consume_server.go +++ b/internal/streamingnode/server/service/handler/consumer/consume_server.go @@ -49,7 +49,7 @@ func CreateConsumeServer(walManager walmanager.Manager, streamServer streamingpb StreamingNodeHandlerService_ConsumeServer: streamServer, } if err := consumeServer.SendCreated(&streamingpb.CreateConsumerResponse{ - WalName: l.WALName(), + WalName: l.WALName().String(), }); err != nil { return nil, errors.Wrap(err, "at send created") } diff --git a/internal/streamingnode/server/service/handler/consumer/consume_server_test.go b/internal/streamingnode/server/service/handler/consumer/consume_server_test.go index fe387aa777..2b6747af52 100644 --- a/internal/streamingnode/server/service/handler/consumer/consume_server_test.go +++ b/internal/streamingnode/server/service/handler/consumer/consume_server_test.go @@ -11,6 +11,7 @@ import ( "github.com/stretchr/testify/mock" "google.golang.org/grpc/metadata" + "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" "github.com/milvus-io/milvus/internal/mocks/streamingnode/server/mock_wal" "github.com/milvus-io/milvus/internal/mocks/streamingnode/server/mock_walmanager" "github.com/milvus-io/milvus/internal/streamingnode/server/resource" @@ -20,7 +21,6 @@ import ( "github.com/milvus-io/milvus/pkg/v2/log" "github.com/milvus-io/milvus/pkg/v2/mocks/proto/mock_streamingpb" "github.com/milvus-io/milvus/pkg/v2/mocks/streaming/util/mock_message" - "github.com/milvus-io/milvus/pkg/v2/proto/messagespb" "github.com/milvus-io/milvus/pkg/v2/proto/streamingpb" "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" "github.com/milvus-io/milvus/pkg/v2/streaming/util/types" @@ -57,7 +57,7 @@ func TestCreateConsumeServer(t *testing.T) { // Return error if send created failed. l := mock_wal.NewMockWAL(t) manager.ExpectedCalls = nil - l.EXPECT().WALName().Return("test") + l.EXPECT().WALName().Return(message.WALNameTest) manager.EXPECT().GetAvailableWAL(types.PChannelInfo{Name: "test", Term: int64(1)}).Return(l, nil) grpcConsumeServer.EXPECT().Send(mock.Anything).Return(errors.New("send created failed")) assertCreateConsumeServerFail(t, manager, grpcConsumeServer) @@ -79,7 +79,7 @@ func TestCreateConsumeServer(t *testing.T) { }, nil) l = mock_wal.NewMockWAL(t) l.EXPECT().Read(mock.Anything, mock.Anything).Return(nil, errors.New("create scanner failed")) - l.EXPECT().WALName().Return("test") + l.EXPECT().WALName().Return(message.WALNameTest) manager.ExpectedCalls = nil manager.EXPECT().GetAvailableWAL(types.PChannelInfo{Name: "test", Term: int64(1)}).Return(l, nil) assertCreateConsumeServerFail(t, manager, grpcConsumeServer) @@ -189,7 +189,7 @@ func TestConsumerServeSendArm(t *testing.T) { // test send. msg := mock_message.NewMockImmutableMessage(t) msg.EXPECT().EstimateSize().Return(0) - msg.EXPECT().IntoImmutableMessageProto().Return(&messagespb.ImmutableMessage{}) + msg.EXPECT().IntoImmutableMessageProto().Return(&commonpb.ImmutableMessage{}) scanCh <- msg // test send txn message. diff --git a/internal/streamingnode/server/service/handler/producer/produce_server.go b/internal/streamingnode/server/service/handler/producer/produce_server.go index 249e4c1fd4..a08bd25fb2 100644 --- a/internal/streamingnode/server/service/handler/producer/produce_server.go +++ b/internal/streamingnode/server/service/handler/producer/produce_server.go @@ -39,7 +39,7 @@ func CreateProduceServer(walManager walmanager.Manager, streamServer streamingpb StreamingNodeHandlerService_ProduceServer: streamServer, } if err := produceServer.SendCreated(&streamingpb.CreateProducerResponse{ - WalName: l.WALName(), + WalName: l.WALName().String(), }); err != nil { return nil, errors.Wrap(err, "at send created") } diff --git a/internal/streamingnode/server/service/handler/producer/produce_server_test.go b/internal/streamingnode/server/service/handler/producer/produce_server_test.go index af825f92c0..4af6e76b49 100644 --- a/internal/streamingnode/server/service/handler/producer/produce_server_test.go +++ b/internal/streamingnode/server/service/handler/producer/produce_server_test.go @@ -14,6 +14,7 @@ import ( "go.uber.org/atomic" "google.golang.org/grpc/metadata" + "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" "github.com/milvus-io/milvus/internal/mocks/streamingnode/server/mock_wal" "github.com/milvus-io/milvus/internal/mocks/streamingnode/server/mock_walmanager" "github.com/milvus-io/milvus/internal/streamingnode/server/resource" @@ -59,9 +60,9 @@ func TestCreateProduceServer(t *testing.T) { // Return error if create scanner failed. l := mock_wal.NewMockWAL(t) - l.EXPECT().WALName().Return("test") + l.EXPECT().WALName().Return(message.WALNameTest) manager.ExpectedCalls = nil - l.EXPECT().WALName().Return("test") + l.EXPECT().WALName().Return(message.WALNameTest) manager.EXPECT().GetAvailableWAL(types.PChannelInfo{Name: "test", Term: 1}).Return(l, nil) grpcProduceServer.EXPECT().Send(mock.Anything).Return(errors.New("send created failed")) assertCreateProduceServerFail(t, manager, grpcProduceServer) @@ -118,7 +119,7 @@ func TestProduceSendArm(t *testing.T) { RequestId: 1, Response: &streamingpb.ProduceMessageResponse_Result{ Result: &streamingpb.ProduceMessageResponseResult{ - Id: &messagespb.MessageID{ + Id: &commonpb.MessageID{ Id: walimplstest.NewTestMessageID(1).Marshal(), }, }, @@ -151,7 +152,7 @@ func TestProduceSendArm(t *testing.T) { RequestId: 1, Response: &streamingpb.ProduceMessageResponse_Result{ Result: &streamingpb.ProduceMessageResponseResult{ - Id: &messagespb.MessageID{ + Id: &commonpb.MessageID{ Id: walimplstest.NewTestMessageID(1).Marshal(), }, }, diff --git a/internal/streamingnode/server/wal/adaptor/builder.go b/internal/streamingnode/server/wal/adaptor/builder.go index afcf392f0f..eb78e0dcea 100644 --- a/internal/streamingnode/server/wal/adaptor/builder.go +++ b/internal/streamingnode/server/wal/adaptor/builder.go @@ -3,6 +3,7 @@ package adaptor import ( "github.com/milvus-io/milvus/internal/streamingnode/server/wal" "github.com/milvus-io/milvus/internal/streamingnode/server/wal/interceptors" + "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" "github.com/milvus-io/milvus/pkg/v2/streaming/walimpls" ) @@ -20,7 +21,7 @@ type builderAdaptorImpl struct { interceptorBuilders []interceptors.InterceptorBuilder } -func (b builderAdaptorImpl) Name() string { +func (b builderAdaptorImpl) Name() message.WALName { return b.builder.Name() } diff --git a/internal/streamingnode/server/wal/adaptor/ro_wal_adaptor.go b/internal/streamingnode/server/wal/adaptor/ro_wal_adaptor.go index 8b7ff99f53..4fbd727226 100644 --- a/internal/streamingnode/server/wal/adaptor/ro_wal_adaptor.go +++ b/internal/streamingnode/server/wal/adaptor/ro_wal_adaptor.go @@ -30,7 +30,7 @@ type roWALAdaptorImpl struct { scanMetrics *metricsutil.ScanMetrics } -func (w *roWALAdaptorImpl) WALName() string { +func (w *roWALAdaptorImpl) WALName() message.WALName { return w.roWALImpls.WALName() } diff --git a/internal/streamingnode/server/wal/adaptor/wal_test.go b/internal/streamingnode/server/wal/adaptor/wal_test.go index 7460c3bb5f..b3444cf638 100644 --- a/internal/streamingnode/server/wal/adaptor/wal_test.go +++ b/internal/streamingnode/server/wal/adaptor/wal_test.go @@ -54,7 +54,7 @@ func TestFencedError(t *testing.T) { func TestWAL(t *testing.T) { initResourceForTest(t) - b := registry.MustGetBuilder(walimplstest.WALName, + b := registry.MustGetBuilder(message.WALNameTest, redo.NewInterceptorBuilder(), lock.NewInterceptorBuilder(), timetick.NewInterceptorBuilder(), diff --git a/internal/streamingnode/server/wal/builder.go b/internal/streamingnode/server/wal/builder.go index d00258273a..57ffec9f9b 100644 --- a/internal/streamingnode/server/wal/builder.go +++ b/internal/streamingnode/server/wal/builder.go @@ -3,13 +3,14 @@ package wal import ( "context" + "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" "github.com/milvus-io/milvus/pkg/v2/streaming/util/types" ) // OpenerBuilder is the interface for build wal opener. type OpenerBuilder interface { // Name of the wal builder, should be a lowercase string. - Name() string + Name() message.WALName Build() (Opener, error) } diff --git a/internal/streamingnode/server/wal/interceptors/chain_interceptor_test.go b/internal/streamingnode/server/wal/interceptors/chain_interceptor_test.go index 5079f4beb4..e418df9ac0 100644 --- a/internal/streamingnode/server/wal/interceptors/chain_interceptor_test.go +++ b/internal/streamingnode/server/wal/interceptors/chain_interceptor_test.go @@ -141,7 +141,7 @@ func testChainInterceptor(t *testing.T, count int, named bool) { msg.EXPECT().MessageType().Return(message.MessageTypeDelete).Maybe() msg.EXPECT().EstimateSize().Return(1).Maybe() msg.EXPECT().TxnContext().Return(nil).Maybe() - mw := metricsutil.NewWriteMetrics(types.PChannelInfo{}, "rocksmq") + mw := metricsutil.NewWriteMetrics(types.PChannelInfo{}, message.WALNameRocksmq) m := mw.StartAppend(msg) ctx := utility.WithAppendMetricsContext(context.Background(), m) msgID, err := interceptor.DoAppend(ctx, msg, func(context.Context, message.MutableMessage) (message.MessageID, error) { diff --git a/internal/streamingnode/server/wal/metricsutil/wal_write.go b/internal/streamingnode/server/wal/metricsutil/wal_write.go index 63e521dd4b..a4d447ec6b 100644 --- a/internal/streamingnode/server/wal/metricsutil/wal_write.go +++ b/internal/streamingnode/server/wal/metricsutil/wal_write.go @@ -12,12 +12,11 @@ import ( "github.com/milvus-io/milvus/pkg/v2/metrics" "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" "github.com/milvus-io/milvus/pkg/v2/streaming/util/types" - "github.com/milvus-io/milvus/pkg/v2/streaming/walimpls/impls/wp" "github.com/milvus-io/milvus/pkg/v2/util/paramtable" ) // NewWriteMetrics creates a new WriteMetrics. -func NewWriteMetrics(pchannel types.PChannelInfo, walName string) *WriteMetrics { +func NewWriteMetrics(pchannel types.PChannelInfo, walName message.WALName) *WriteMetrics { constLabel := prometheus.Labels{ metrics.NodeIDLabelName: paramtable.GetStringNodeID(), metrics.WALChannelLabelName: pchannel.Name, @@ -26,18 +25,18 @@ func NewWriteMetrics(pchannel types.PChannelInfo, walName string) *WriteMetrics paramtable.GetStringNodeID(), pchannel.Name, strconv.FormatInt(pchannel.Term, 10), - walName).Set(1) + walName.String()).Set(1) slowLogThreshold := paramtable.Get().StreamingCfg.LoggingAppendSlowThreshold.GetAsDurationByParse() if slowLogThreshold <= 0 { slowLogThreshold = time.Second } - if walName == wp.WALName && slowLogThreshold < 3*time.Second { + if walName == message.WALNameWoodpecker && slowLogThreshold < 3*time.Second { // woodpecker wal is always slow, so we need to set a higher threshold by default. slowLogThreshold = 3 * time.Second } return &WriteMetrics{ - walName: walName, + walName: walName.String(), pchannel: pchannel, constLabel: constLabel, bytes: metrics.WALAppendMessageBytes.MustCurryWith(constLabel), diff --git a/internal/streamingnode/server/wal/recovery/checkpoint.go b/internal/streamingnode/server/wal/recovery/checkpoint.go deleted file mode 100644 index 5c55a1b40f..0000000000 --- a/internal/streamingnode/server/wal/recovery/checkpoint.go +++ /dev/null @@ -1,49 +0,0 @@ -package recovery - -import ( - "github.com/milvus-io/milvus/pkg/v2/proto/messagespb" - "github.com/milvus-io/milvus/pkg/v2/proto/streamingpb" - "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" -) - -const ( - RecoveryMagicStreamingInitialized int64 = 1 // the vchannel info is set into the catalog. - // the checkpoint is set into the catalog. -) - -// newWALCheckpointFromProto creates a new WALCheckpoint from a protobuf message. -func newWALCheckpointFromProto(walName string, cp *streamingpb.WALCheckpoint) *WALCheckpoint { - return &WALCheckpoint{ - MessageID: message.MustUnmarshalMessageID(walName, cp.MessageId.Id), - TimeTick: cp.TimeTick, - Magic: cp.RecoveryMagic, - } -} - -// WALCheckpoint represents a consume checkpoint in the Write-Ahead Log (WAL). -type WALCheckpoint struct { - MessageID message.MessageID - TimeTick uint64 - Magic int64 -} - -// IntoProto converts the WALCheckpoint to a protobuf message. -func (c *WALCheckpoint) IntoProto() *streamingpb.WALCheckpoint { - cp := &streamingpb.WALCheckpoint{ - MessageId: &messagespb.MessageID{ - Id: c.MessageID.Marshal(), - }, - TimeTick: c.TimeTick, - RecoveryMagic: c.Magic, - } - return cp -} - -// Clone creates a new WALCheckpoint with the same values as the original. -func (c *WALCheckpoint) Clone() *WALCheckpoint { - return &WALCheckpoint{ - MessageID: c.MessageID, - TimeTick: c.TimeTick, - Magic: c.Magic, - } -} diff --git a/internal/streamingnode/server/wal/recovery/checkpoint_test.go b/internal/streamingnode/server/wal/recovery/checkpoint_test.go deleted file mode 100644 index ed55dbbc4f..0000000000 --- a/internal/streamingnode/server/wal/recovery/checkpoint_test.go +++ /dev/null @@ -1,39 +0,0 @@ -package recovery - -import ( - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/milvus-io/milvus/pkg/v2/proto/messagespb" - "github.com/milvus-io/milvus/pkg/v2/proto/streamingpb" - "github.com/milvus-io/milvus/pkg/v2/streaming/walimpls/impls/rmq" -) - -func TestNewWALCheckpointFromProto(t *testing.T) { - walName := "rocksmq" - messageID := rmq.NewRmqID(1) - timeTick := uint64(12345) - recoveryMagic := int64(1) - protoCheckpoint := &streamingpb.WALCheckpoint{ - MessageId: &messagespb.MessageID{Id: messageID.Marshal()}, - TimeTick: timeTick, - RecoveryMagic: recoveryMagic, - } - checkpoint := newWALCheckpointFromProto(walName, protoCheckpoint) - - assert.True(t, messageID.EQ(checkpoint.MessageID)) - assert.Equal(t, timeTick, checkpoint.TimeTick) - assert.Equal(t, recoveryMagic, checkpoint.Magic) - - proto := checkpoint.IntoProto() - checkpoint2 := newWALCheckpointFromProto(walName, proto) - assert.True(t, messageID.EQ(checkpoint2.MessageID)) - assert.Equal(t, timeTick, checkpoint2.TimeTick) - assert.Equal(t, recoveryMagic, checkpoint2.Magic) - - checkpoint3 := checkpoint.Clone() - assert.True(t, messageID.EQ(checkpoint3.MessageID)) - assert.Equal(t, timeTick, checkpoint3.TimeTick) - assert.Equal(t, recoveryMagic, checkpoint3.Magic) -} diff --git a/internal/streamingnode/server/wal/recovery/recovery_persisted.go b/internal/streamingnode/server/wal/recovery/recovery_persisted.go index e8331c3a25..1df0a14678 100644 --- a/internal/streamingnode/server/wal/recovery/recovery_persisted.go +++ b/internal/streamingnode/server/wal/recovery/recovery_persisted.go @@ -10,10 +10,10 @@ import ( "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" "github.com/milvus-io/milvus-proto/go-api/v2/milvuspb" "github.com/milvus-io/milvus/internal/streamingnode/server/resource" + "github.com/milvus-io/milvus/internal/streamingnode/server/wal/utility" "github.com/milvus-io/milvus/pkg/v2/log" "github.com/milvus-io/milvus/pkg/v2/proto/datapb" "github.com/milvus-io/milvus/pkg/v2/proto/etcdpb" - "github.com/milvus-io/milvus/pkg/v2/proto/messagespb" "github.com/milvus-io/milvus/pkg/v2/proto/rootcoordpb" "github.com/milvus-io/milvus/pkg/v2/proto/streamingpb" "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" @@ -25,7 +25,7 @@ import ( ) // recoverRecoveryInfoFromMeta retrieves the recovery info for the given channel. -func (r *recoveryStorageImpl) recoverRecoveryInfoFromMeta(ctx context.Context, walName string, channelInfo types.PChannelInfo, lastTimeTickMessage message.ImmutableMessage) error { +func (r *recoveryStorageImpl) recoverRecoveryInfoFromMeta(ctx context.Context, channelInfo types.PChannelInfo, lastTimeTickMessage message.ImmutableMessage) error { r.metrics.ObserveStateChange(recoveryStorageStatePersistRecovering) r.SetLogger(resource.Resource().Logger().With( log.FieldComponent(componentRecoveryStorage), @@ -44,7 +44,7 @@ func (r *recoveryStorageImpl) recoverRecoveryInfoFromMeta(ctx context.Context, w return errors.Wrap(err, "failed to initialize checkpoint") } } - r.checkpoint = newWALCheckpointFromProto(walName, cpProto) + r.checkpoint = utility.NewWALCheckpointFromProto(cpProto) r.Logger().Info("recover checkpoint done", zap.String("checkpoint", r.checkpoint.MessageID.String()), zap.Uint64("timetick", r.checkpoint.TimeTick), @@ -156,9 +156,7 @@ func (r *recoveryStorageImpl) initializeRecoverInfo(ctx context.Context, channel } // Use the first timesync message as the initial checkpoint. checkpoint := &streamingpb.WALCheckpoint{ - MessageId: &messagespb.MessageID{ - Id: untilMessage.LastConfirmedMessageID().Marshal(), - }, + MessageId: untilMessage.LastConfirmedMessageID().IntoProto(), TimeTick: untilMessage.TimeTick(), RecoveryMagic: RecoveryMagicStreamingInitialized, } diff --git a/internal/streamingnode/server/wal/recovery/recovery_persisted_test.go b/internal/streamingnode/server/wal/recovery/recovery_persisted_test.go index 2fdd8ce5fc..64289c943c 100644 --- a/internal/streamingnode/server/wal/recovery/recovery_persisted_test.go +++ b/internal/streamingnode/server/wal/recovery/recovery_persisted_test.go @@ -19,7 +19,6 @@ import ( internaltypes "github.com/milvus-io/milvus/internal/types" "github.com/milvus-io/milvus/pkg/v2/proto/datapb" "github.com/milvus-io/milvus/pkg/v2/proto/etcdpb" - "github.com/milvus-io/milvus/pkg/v2/proto/messagespb" "github.com/milvus-io/milvus/pkg/v2/proto/rootcoordpb" "github.com/milvus-io/milvus/pkg/v2/proto/streamingpb" "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" @@ -48,20 +47,17 @@ func TestInitRecoveryInfoFromMeta(t *testing.T) { snCatalog.EXPECT().GetConsumeCheckpoint(mock.Anything, mock.Anything).Return( &streamingpb.WALCheckpoint{ - MessageId: &messagespb.MessageID{ - Id: rmq.NewRmqID(1).Marshal(), - }, + MessageId: rmq.NewRmqID(1).IntoProto(), TimeTick: 1, RecoveryMagic: RecoveryMagicStreamingInitialized, }, nil) resource.InitForTest(t, resource.OptStreamingNodeCatalog(snCatalog)) - walName := "rocksmq" channel := types.PChannelInfo{Name: "test_channel"} lastConfirmed := message.CreateTestTimeTickSyncMessage(t, 1, 1, rmq.NewRmqID(1)) rs := newRecoveryStorage(channel) - err := rs.recoverRecoveryInfoFromMeta(context.Background(), walName, channel, lastConfirmed.IntoImmutableMessage(rmq.NewRmqID(1))) + err := rs.recoverRecoveryInfoFromMeta(context.Background(), channel, lastConfirmed.IntoImmutableMessage(rmq.NewRmqID(1))) assert.NoError(t, err) assert.NotNil(t, rs.checkpoint) assert.Equal(t, RecoveryMagicStreamingInitialized, rs.checkpoint.Magic) @@ -136,12 +132,11 @@ func TestInitRecoveryInfoFromCoord(t *testing.T) { fc.Set(c) resource.InitForTest(t, resource.OptStreamingNodeCatalog(snCatalog), resource.OptMixCoordClient(fc)) - walName := "rocksmq" channel := types.PChannelInfo{Name: "test_channel"} lastConfirmed := message.CreateTestTimeTickSyncMessage(t, 1, 1, rmq.NewRmqID(1)) rs := newRecoveryStorage(channel) - err := rs.recoverRecoveryInfoFromMeta(context.Background(), walName, channel, lastConfirmed.IntoImmutableMessage(rmq.NewRmqID(1))) + err := rs.recoverRecoveryInfoFromMeta(context.Background(), channel, lastConfirmed.IntoImmutableMessage(rmq.NewRmqID(1))) assert.NoError(t, err) assert.NotNil(t, rs.checkpoint) assert.Len(t, rs.vchannels, 2) diff --git a/internal/streamingnode/server/wal/recovery/recovery_storage.go b/internal/streamingnode/server/wal/recovery/recovery_storage.go index 9821844b14..f772373919 100644 --- a/internal/streamingnode/server/wal/recovery/recovery_storage.go +++ b/internal/streamingnode/server/wal/recovery/recovery_storage.go @@ -11,6 +11,10 @@ import ( "github.com/milvus-io/milvus/pkg/v2/streaming/walimpls" ) +type WALCheckpoint = utility.WALCheckpoint + +const RecoveryMagicStreamingInitialized = utility.RecoveryMagicStreamingInitialized + // RecoverySnapshot is the snapshot of the recovery info. type RecoverySnapshot struct { VChannels map[string]*streamingpb.VChannelMeta @@ -32,7 +36,7 @@ type RecoveryMetrics struct { // RecoveryStreamBuilder is an interface that is used to build a recovery stream from the WAL. type RecoveryStreamBuilder interface { // WALName returns the name of the WAL. - WALName() string + WALName() message.WALName // Channel returns the channel info of wal. Channel() types.PChannelInfo diff --git a/internal/streamingnode/server/wal/recovery/recovery_storage_impl.go b/internal/streamingnode/server/wal/recovery/recovery_storage_impl.go index be9d1b824b..7b9403a194 100644 --- a/internal/streamingnode/server/wal/recovery/recovery_storage_impl.go +++ b/internal/streamingnode/server/wal/recovery/recovery_storage_impl.go @@ -35,7 +35,7 @@ func RecoverRecoveryStorage( lastTimeTickMessage message.ImmutableMessage, ) (RecoveryStorage, *RecoverySnapshot, error) { rs := newRecoveryStorage(recoveryStreamBuilder.Channel()) - if err := rs.recoverRecoveryInfoFromMeta(ctx, recoveryStreamBuilder.WALName(), recoveryStreamBuilder.Channel(), lastTimeTickMessage); err != nil { + if err := rs.recoverRecoveryInfoFromMeta(ctx, recoveryStreamBuilder.Channel(), lastTimeTickMessage); err != nil { rs.Logger().Warn("recovery storage failed", zap.Error(err)) return nil, nil, err } diff --git a/internal/streamingnode/server/wal/recovery/recovery_storage_test.go b/internal/streamingnode/server/wal/recovery/recovery_storage_test.go index 5447b873bc..fdfdaaeecf 100644 --- a/internal/streamingnode/server/wal/recovery/recovery_storage_test.go +++ b/internal/streamingnode/server/wal/recovery/recovery_storage_test.go @@ -37,9 +37,7 @@ func TestRecoveryStorage(t *testing.T) { vchannelMetas := make(map[string]*streamingpb.VChannelMeta) segmentMetas := make(map[int64]*streamingpb.SegmentAssignmentMeta) cp := &streamingpb.WALCheckpoint{ - MessageId: &messagespb.MessageID{ - Id: rmq.NewRmqID(1).Marshal(), - }, + MessageId: rmq.NewRmqID(1).IntoProto(), TimeTick: 1, RecoveryMagic: 0, } @@ -233,8 +231,8 @@ func (ts *testRecoveryStream) Close() error { return nil } -func (b *streamBuilder) WALName() string { - return "rocksmq" +func (b *streamBuilder) WALName() message.WALName { + return message.WALNameRocksmq } func (b *streamBuilder) Channel() types.PChannelInfo { diff --git a/internal/streamingnode/server/wal/registry/registry.go b/internal/streamingnode/server/wal/registry/registry.go index 9648aa7ddb..69e9f33e8e 100644 --- a/internal/streamingnode/server/wal/registry/registry.go +++ b/internal/streamingnode/server/wal/registry/registry.go @@ -4,11 +4,12 @@ import ( "github.com/milvus-io/milvus/internal/streamingnode/server/wal" "github.com/milvus-io/milvus/internal/streamingnode/server/wal/adaptor" "github.com/milvus-io/milvus/internal/streamingnode/server/wal/interceptors" + "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" "github.com/milvus-io/milvus/pkg/v2/streaming/walimpls/registry" ) // MustGetBuilder returns the wal builder by name. -func MustGetBuilder(name string, interceptorBuilders ...interceptors.InterceptorBuilder) wal.OpenerBuilder { +func MustGetBuilder(name message.WALName, interceptorBuilders ...interceptors.InterceptorBuilder) wal.OpenerBuilder { b := registry.MustGetBuilder(name) return adaptor.AdaptImplsToBuilder(b, interceptorBuilders...) } diff --git a/internal/streamingnode/server/wal/utility/checkpoint.go b/internal/streamingnode/server/wal/utility/checkpoint.go new file mode 100644 index 0000000000..39c0fce419 --- /dev/null +++ b/internal/streamingnode/server/wal/utility/checkpoint.go @@ -0,0 +1,116 @@ +package utility + +import ( + "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" + "github.com/milvus-io/milvus/pkg/v2/proto/streamingpb" + "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" +) + +const ( + RecoveryMagicStreamingInitialized int64 = 1 // the vchannel info is set into the catalog. + // the checkpoint is set into the catalog. +) + +// NewWALCheckpointFromProto creates a new WALCheckpoint from a protobuf message. +func NewWALCheckpointFromProto(cp *streamingpb.WALCheckpoint) *WALCheckpoint { + wcp := &WALCheckpoint{ + MessageID: message.MustUnmarshalMessageID(cp.MessageId), + TimeTick: cp.TimeTick, + Magic: cp.RecoveryMagic, + ReplicateConfig: cp.ReplicateConfig, + } + if cp.ReplicateCheckpoint != nil { + var messageID message.MessageID + if cp.ReplicateCheckpoint.MessageId != nil { + messageID = message.MustUnmarshalMessageID(cp.ReplicateCheckpoint.MessageId) + } + wcp.ReplicateCheckpoint = &ReplicateCheckpoint{ + ClusterID: cp.ReplicateCheckpoint.ClusterId, + PChannel: cp.ReplicateCheckpoint.Pchannel, + MessageID: messageID, + TimeTick: cp.ReplicateCheckpoint.TimeTick, + } + } + return wcp +} + +// WALCheckpoint represents a consume checkpoint in the Write-Ahead Log (WAL). +type WALCheckpoint struct { + MessageID message.MessageID + TimeTick uint64 + Magic int64 + ReplicateCheckpoint *ReplicateCheckpoint + ReplicateConfig *commonpb.ReplicateConfiguration +} + +// IntoProto converts the WALCheckpoint to a protobuf message. +func (c *WALCheckpoint) IntoProto() *streamingpb.WALCheckpoint { + cp := &streamingpb.WALCheckpoint{ + MessageId: c.MessageID.IntoProto(), + TimeTick: c.TimeTick, + RecoveryMagic: c.Magic, + } + if c.ReplicateCheckpoint != nil { + cp.ReplicateCheckpoint = c.ReplicateCheckpoint.IntoProto() + } + return cp +} + +// Clone creates a new WALCheckpoint with the same values as the original. +func (c *WALCheckpoint) Clone() *WALCheckpoint { + return &WALCheckpoint{ + MessageID: c.MessageID, + TimeTick: c.TimeTick, + Magic: c.Magic, + ReplicateCheckpoint: c.ReplicateCheckpoint.Clone(), + } +} + +// NewReplicateCheckpointFromProto creates a new ReplicateCheckpoint from a protobuf message. +func NewReplicateCheckpointFromProto(cp *commonpb.ReplicateCheckpoint) *ReplicateCheckpoint { + return &ReplicateCheckpoint{ + ClusterID: cp.ClusterId, + PChannel: cp.Pchannel, + MessageID: message.MustUnmarshalMessageID(cp.MessageId), + TimeTick: cp.TimeTick, + } +} + +// ReplicateCheckpoint represents a source milvus cluster checkpoint. +// It's used to recover the replication state for remote source cluster. +type ReplicateCheckpoint struct { + ClusterID string // the cluster id of the source cluster. + PChannel string // the pchannel of the source cluster. + MessageID message.MessageID // the last confirmed message id of the last replicated message. + TimeTick uint64 // the time tick of the last replicated message. +} + +// IntoProto converts the ReplicateCheckpoint to a protobuf message. +func (c *ReplicateCheckpoint) IntoProto() *commonpb.ReplicateCheckpoint { + if c == nil { + return nil + } + var messageID *commonpb.MessageID + if c.MessageID != nil { + messageID = c.MessageID.IntoProto() + } + return &commonpb.ReplicateCheckpoint{ + ClusterId: c.ClusterID, + Pchannel: c.PChannel, + MessageId: messageID, + TimeTick: c.TimeTick, + } +} + +// Clone creates a new ReplicateCheckpoint with the same values as the original. +func (c *ReplicateCheckpoint) Clone() *ReplicateCheckpoint { + if c == nil { + return nil + } + return &ReplicateCheckpoint{ + ClusterID: c.ClusterID, + PChannel: c.PChannel, + MessageID: c.MessageID, + TimeTick: c.TimeTick, + } +} diff --git a/internal/streamingnode/server/wal/utility/checkpoint_test.go b/internal/streamingnode/server/wal/utility/checkpoint_test.go new file mode 100644 index 0000000000..b52c3c76bf --- /dev/null +++ b/internal/streamingnode/server/wal/utility/checkpoint_test.go @@ -0,0 +1,62 @@ +package utility + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" + "github.com/milvus-io/milvus/pkg/v2/proto/streamingpb" + "github.com/milvus-io/milvus/pkg/v2/streaming/walimpls/impls/rmq" +) + +func TestNewWALCheckpointFromProto(t *testing.T) { + messageID := rmq.NewRmqID(1) + timeTick := uint64(12345) + recoveryMagic := int64(1) + protoCheckpoint := &streamingpb.WALCheckpoint{ + MessageId: messageID.IntoProto(), + TimeTick: timeTick, + RecoveryMagic: recoveryMagic, + } + checkpoint := NewWALCheckpointFromProto(protoCheckpoint) + + assert.True(t, messageID.EQ(checkpoint.MessageID)) + assert.Equal(t, timeTick, checkpoint.TimeTick) + assert.Equal(t, recoveryMagic, checkpoint.Magic) + + proto := checkpoint.IntoProto() + checkpoint2 := NewWALCheckpointFromProto(proto) + assert.True(t, messageID.EQ(checkpoint2.MessageID)) + assert.Equal(t, timeTick, checkpoint2.TimeTick) + assert.Equal(t, recoveryMagic, checkpoint2.Magic) + + checkpoint3 := checkpoint.Clone() + assert.True(t, messageID.EQ(checkpoint3.MessageID)) + assert.Equal(t, timeTick, checkpoint3.TimeTick) + assert.Equal(t, recoveryMagic, checkpoint3.Magic) + + protoCheckpoint.ReplicateConfig = &commonpb.ReplicateConfiguration{} + protoCheckpoint.ReplicateCheckpoint = &commonpb.ReplicateCheckpoint{ + ClusterId: "by-dev", + Pchannel: "p1", + MessageId: nil, + TimeTick: 0, + } + newCheckpoint := NewWALCheckpointFromProto(protoCheckpoint) + assert.Equal(t, "by-dev", newCheckpoint.ReplicateCheckpoint.ClusterID) + assert.Equal(t, "p1", newCheckpoint.ReplicateCheckpoint.PChannel) + assert.Equal(t, uint64(0), newCheckpoint.ReplicateCheckpoint.TimeTick) + assert.Nil(t, newCheckpoint.ReplicateCheckpoint.MessageID) + assert.NotNil(t, newCheckpoint.ReplicateConfig) + + protoCheckpoint.ReplicateCheckpoint.MessageId = rmq.NewRmqID(2).IntoProto() + protoCheckpoint.ReplicateCheckpoint.TimeTick = 123456 + + newCheckpoint = NewWALCheckpointFromProto(protoCheckpoint) + assert.Equal(t, "by-dev", newCheckpoint.ReplicateCheckpoint.ClusterID) + assert.Equal(t, "p1", newCheckpoint.ReplicateCheckpoint.PChannel) + assert.Equal(t, uint64(123456), newCheckpoint.ReplicateCheckpoint.TimeTick) + assert.True(t, rmq.NewRmqID(2).EQ(newCheckpoint.ReplicateCheckpoint.MessageID)) + assert.NotNil(t, newCheckpoint.ReplicateConfig) +} diff --git a/internal/streamingnode/server/wal/wal.go b/internal/streamingnode/server/wal/wal.go index a55ef828e8..6153ca85a3 100644 --- a/internal/streamingnode/server/wal/wal.go +++ b/internal/streamingnode/server/wal/wal.go @@ -3,11 +3,15 @@ package wal import ( "context" + "github.com/milvus-io/milvus/internal/streamingnode/server/wal/utility" "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" "github.com/milvus-io/milvus/pkg/v2/streaming/util/types" ) -type AppendResult = types.AppendResult +type ( + AppendResult = types.AppendResult + ReplicateCheckpoint = utility.ReplicateCheckpoint +) // WAL is the WAL framework interface. // !!! Don't implement it directly, implement walimpls.WAL instead. @@ -29,7 +33,7 @@ type WAL interface { // !!! Don't implement it directly, implement walimpls.WAL instead. type ROWAL interface { // WALName returns the name of the wal. - WALName() string + WALName() message.WALName // Metrics returns the metrics of the wal. Metrics() types.WALMetrics diff --git a/internal/streamingnode/server/walmanager/manager_impl.go b/internal/streamingnode/server/walmanager/manager_impl.go index 76295fb2ea..7d84bbf579 100644 --- a/internal/streamingnode/server/walmanager/manager_impl.go +++ b/internal/streamingnode/server/walmanager/manager_impl.go @@ -24,7 +24,7 @@ var errWALManagerClosed = status.NewOnShutdownError("wal manager is closed") // OpenManager create a wal manager. func OpenManager() (Manager, error) { walName := util.MustSelectWALName() - resource.Resource().Logger().Info("open wal manager", zap.String("walName", walName)) + resource.Resource().Logger().Info("open wal manager", zap.Stringer("walName", walName)) opener, err := registry.MustGetBuilder(walName, redo.NewInterceptorBuilder(), lock.NewInterceptorBuilder(), diff --git a/internal/util/streamingutil/service/contextutil/cluster_id.go b/internal/util/streamingutil/service/contextutil/cluster_id.go new file mode 100644 index 0000000000..a43b94ee7d --- /dev/null +++ b/internal/util/streamingutil/service/contextutil/cluster_id.go @@ -0,0 +1,31 @@ +package contextutil + +import ( + "context" + + "github.com/cockroachdb/errors" + "google.golang.org/grpc/metadata" +) + +const clusterIDKey = "cluster-id" + +// WithClusterID attaches cluster id to context. +func WithClusterID(ctx context.Context, clusterID string) context.Context { + return metadata.AppendToOutgoingContext(ctx, clusterIDKey, clusterID) +} + +// GetClusterID gets cluster id from context. +func GetClusterID(ctx context.Context) (string, error) { + md, ok := metadata.FromIncomingContext(ctx) + if !ok { + return "", errors.New("cluster id not found from context") + } + msg := md.Get(clusterIDKey) + if len(msg) == 0 { + return "", errors.New("cluster id not found in context") + } + if msg[0] == "" { + return "", errors.New("cluster id is empty") + } + return msg[0], nil +} diff --git a/internal/util/streamingutil/service/contextutil/cluster_id_test.go b/internal/util/streamingutil/service/contextutil/cluster_id_test.go new file mode 100644 index 0000000000..2135e0df00 --- /dev/null +++ b/internal/util/streamingutil/service/contextutil/cluster_id_test.go @@ -0,0 +1,46 @@ +package contextutil + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + "google.golang.org/grpc/metadata" +) + +func TestWithClusterID(t *testing.T) { + ctx := WithClusterID(context.Background(), "test-cluster-id") + + md, ok := metadata.FromOutgoingContext(ctx) + assert.True(t, ok) + assert.NotNil(t, md) + + ctx = metadata.NewIncomingContext(context.Background(), md) + clusterID, err := GetClusterID(ctx) + assert.Nil(t, err) + assert.Equal(t, "test-cluster-id", clusterID) + + // panic case. + assert.NotPanics(t, func() { WithClusterID(context.Background(), "") }) +} + +func TestGetClusterID(t *testing.T) { + // empty context. + clusterID, err := GetClusterID(context.Background()) + assert.Error(t, err) + assert.Empty(t, clusterID) + + // key not exist. + md := metadata.New(map[string]string{}) + clusterID, err = GetClusterID(metadata.NewIncomingContext(context.Background(), md)) + assert.Error(t, err) + assert.Empty(t, clusterID) + + // invalid value. + md = metadata.New(map[string]string{ + clusterIDKey: "", + }) + clusterID, err = GetClusterID(metadata.NewIncomingContext(context.Background(), md)) + assert.Error(t, err) + assert.Empty(t, clusterID) +} diff --git a/internal/util/streamingutil/service/contextutil/create_producer.go b/internal/util/streamingutil/service/contextutil/create_producer.go index 788a332c69..347f856045 100644 --- a/internal/util/streamingutil/service/contextutil/create_producer.go +++ b/internal/util/streamingutil/service/contextutil/create_producer.go @@ -12,9 +12,7 @@ import ( "github.com/milvus-io/milvus/pkg/v2/proto/streamingpb" ) -const ( - createProducerKey = "create-producer" -) +const createProducerKey = "create-producer" // WithCreateProducer attaches create producer request to context. func WithCreateProducer(ctx context.Context, req *streamingpb.CreateProducerRequest) context.Context { diff --git a/internal/util/streamingutil/status/streaming_error.go b/internal/util/streamingutil/status/streaming_error.go index a3e6c08135..43997005e3 100644 --- a/internal/util/streamingutil/status/streaming_error.go +++ b/internal/util/streamingutil/status/streaming_error.go @@ -41,16 +41,23 @@ func (e *StreamingError) IsFenced() bool { return e.Code == streamingpb.StreamingCode_STREAMING_CODE_CHANNEL_FENCED } +// IsIgnoredOperation returns true if the operation is ignored. +func (e *StreamingError) IsIgnoredOperation() bool { + return e.Code == streamingpb.StreamingCode_STREAMING_CODE_IGNORED_OPERATION +} + // IsSkippedOperation returns true if the operation is ignored or skipped. func (e *StreamingError) IsSkippedOperation() bool { - return e.Code == streamingpb.StreamingCode_STREAMING_CODE_IGNORED_OPERATION || + return e.IsIgnoredOperation() || e.Code == streamingpb.StreamingCode_STREAMING_CODE_UNMATCHED_CHANNEL_TERM } // IsUnrecoverable returns true if the error is unrecoverable. // Stop resuming retry and report to user. func (e *StreamingError) IsUnrecoverable() bool { - return e.Code == streamingpb.StreamingCode_STREAMING_CODE_UNRECOVERABLE || e.IsTxnUnavilable() + return e.Code == streamingpb.StreamingCode_STREAMING_CODE_UNRECOVERABLE || + e.Code == streamingpb.StreamingCode_STREAMING_CODE_REPLICATE_VIOLATION || + e.IsTxnUnavilable() } // IsTxnUnavilable returns true if the transaction is unavailable. @@ -129,6 +136,11 @@ func NewUnrecoverableError(format string, args ...interface{}) *StreamingError { return New(streamingpb.StreamingCode_STREAMING_CODE_UNRECOVERABLE, format, args...) } +// NewReplicateViolation creates a new StreamingError with code STREAMING_CODE_REPLICATE_VIOLATION. +func NewReplicateViolation(format string, args ...interface{}) *StreamingError { + return New(streamingpb.StreamingCode_STREAMING_CODE_REPLICATE_VIOLATION, format, args...) +} + // NewResourceAcquired creates a new StreamingError with code STREAMING_CODE_RESOURCE_ACQUIRED. func NewResourceAcquired(format string, args ...interface{}) *StreamingError { return New(streamingpb.StreamingCode_STREAMING_CODE_RESOURCE_ACQUIRED, format, args...) diff --git a/internal/util/streamingutil/util/wal_selector.go b/internal/util/streamingutil/util/wal_selector.go index f37f7ccb5d..b02c0a8abf 100644 --- a/internal/util/streamingutil/util/wal_selector.go +++ b/internal/util/streamingutil/util/wal_selector.go @@ -3,16 +3,13 @@ package util import ( "github.com/cockroachdb/errors" + "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" "github.com/milvus-io/milvus/pkg/v2/util/paramtable" "github.com/milvus-io/milvus/pkg/v2/util/typeutil" ) const ( - walTypeDefault = "default" - WALTypeRocksmq = "rocksmq" - WALTypeKafka = "kafka" - WALTypePulsar = "pulsar" - WALTypeWoodpecker = "woodpecker" + walTypeDefault = "default" ) type walEnable struct { @@ -22,8 +19,14 @@ type walEnable struct { Woodpecker bool } +// InitAndSelectWALName init and select wal name. +func InitAndSelectWALName() { + walName := MustSelectWALName() + message.RegisterDefaultWALName(walName) +} + // MustSelectWALName select wal name. -func MustSelectWALName() string { +func MustSelectWALName() message.WALName { standalone := paramtable.GetRole() == typeutil.StandaloneRole params := paramtable.Get() return mustSelectWALName(standalone, params.MQCfg.Type.GetValue(), walEnable{ @@ -35,37 +38,43 @@ func MustSelectWALName() string { } // mustSelectWALName select wal name. -func mustSelectWALName(standalone bool, mqType string, enable walEnable) string { +func mustSelectWALName(standalone bool, mqType string, enable walEnable) message.WALName { if mqType != walTypeDefault { - if err := validateWALName(standalone, mqType); err != nil { + mqName, err := validateWALName(standalone, mqType) + if err != nil { panic(err) } - return mqType + return mqName } if standalone { if enable.Rocksmq { - return WALTypeRocksmq + return message.WALNameRocksmq } } if enable.Pulsar { - return WALTypePulsar + return message.WALNamePulsar } if enable.Kafka { - return WALTypeKafka + return message.WALNameKafka } if enable.Woodpecker { - return WALTypeWoodpecker + return message.WALNameWoodpecker } panic(errors.Errorf("no available wal config found, %s, enable: %+v", mqType, enable)) } // Validate mq type. -func validateWALName(standalone bool, mqType string) error { +func validateWALName(standalone bool, mqType string) (message.WALName, error) { + mqName := message.NewWALName(mqType) + if mqName == message.WALNameUnknown || mqName == message.WALNameTest { + return mqName, errors.Errorf("mq %s is not valid", mqType) + } + // we may register more mq type by plugin. // so we should not check all mq type here. // only check standalone type. - if !standalone && mqType == WALTypeRocksmq { - return errors.Newf("mq %s is only valid in standalone mode", mqType) + if !standalone && mqName == message.WALNameRocksmq { + return mqName, errors.Newf("mq %s is only valid in standalone mode", mqType) } - return nil + return mqName, nil } diff --git a/internal/util/streamingutil/util/wal_selector_test.go b/internal/util/streamingutil/util/wal_selector_test.go index 928d05e4e5..ec45e0d469 100644 --- a/internal/util/streamingutil/util/wal_selector_test.go +++ b/internal/util/streamingutil/util/wal_selector_test.go @@ -4,30 +4,33 @@ import ( "testing" "github.com/stretchr/testify/assert" + + "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" ) func TestValidateWALType(t *testing.T) { - assert.Error(t, validateWALName(false, WALTypeRocksmq)) + _, err := validateWALName(false, message.WALNameRocksmq.String()) + assert.Error(t, err) } func TestSelectWALType(t *testing.T) { - assert.Equal(t, mustSelectWALName(true, walTypeDefault, walEnable{true, true, true, true}), WALTypeRocksmq) - assert.Equal(t, mustSelectWALName(true, walTypeDefault, walEnable{false, true, true, true}), WALTypePulsar) - assert.Equal(t, mustSelectWALName(true, walTypeDefault, walEnable{false, false, true, true}), WALTypeKafka) - assert.Equal(t, mustSelectWALName(true, walTypeDefault, walEnable{false, false, false, true}), WALTypeWoodpecker) + assert.Equal(t, mustSelectWALName(true, walTypeDefault, walEnable{true, true, true, true}), message.WALNameRocksmq) + assert.Equal(t, mustSelectWALName(true, walTypeDefault, walEnable{false, true, true, true}), message.WALNamePulsar) + assert.Equal(t, mustSelectWALName(true, walTypeDefault, walEnable{false, false, true, true}), message.WALNameKafka) + assert.Equal(t, mustSelectWALName(true, walTypeDefault, walEnable{false, false, false, true}), message.WALNameWoodpecker) assert.Panics(t, func() { mustSelectWALName(true, walTypeDefault, walEnable{false, false, false, false}) }) - assert.Equal(t, mustSelectWALName(false, walTypeDefault, walEnable{true, true, true, true}), WALTypePulsar) - assert.Equal(t, mustSelectWALName(false, walTypeDefault, walEnable{false, true, true, true}), WALTypePulsar) - assert.Equal(t, mustSelectWALName(false, walTypeDefault, walEnable{false, true, true, true}), WALTypePulsar) - assert.Equal(t, mustSelectWALName(false, walTypeDefault, walEnable{false, false, true, true}), WALTypeKafka) - assert.Equal(t, mustSelectWALName(false, walTypeDefault, walEnable{false, false, false, true}), WALTypeWoodpecker) + assert.Equal(t, mustSelectWALName(false, walTypeDefault, walEnable{true, true, true, true}), message.WALNamePulsar) + assert.Equal(t, mustSelectWALName(false, walTypeDefault, walEnable{false, true, true, true}), message.WALNamePulsar) + assert.Equal(t, mustSelectWALName(false, walTypeDefault, walEnable{false, true, true, true}), message.WALNamePulsar) + assert.Equal(t, mustSelectWALName(false, walTypeDefault, walEnable{false, false, true, true}), message.WALNameKafka) + assert.Equal(t, mustSelectWALName(false, walTypeDefault, walEnable{false, false, false, true}), message.WALNameWoodpecker) assert.Panics(t, func() { mustSelectWALName(false, walTypeDefault, walEnable{false, false, false, false}) }) - assert.Equal(t, mustSelectWALName(true, WALTypeRocksmq, walEnable{true, true, true, true}), WALTypeRocksmq) - assert.Equal(t, mustSelectWALName(true, WALTypePulsar, walEnable{true, true, true, true}), WALTypePulsar) - assert.Equal(t, mustSelectWALName(true, WALTypeKafka, walEnable{true, true, true, true}), WALTypeKafka) - assert.Equal(t, mustSelectWALName(true, WALTypeWoodpecker, walEnable{true, true, true, true}), WALTypeWoodpecker) - assert.Panics(t, func() { mustSelectWALName(false, WALTypeRocksmq, walEnable{true, true, true, true}) }) - assert.Equal(t, mustSelectWALName(false, WALTypePulsar, walEnable{true, true, true, true}), WALTypePulsar) - assert.Equal(t, mustSelectWALName(false, WALTypeKafka, walEnable{true, true, true, true}), WALTypeKafka) - assert.Equal(t, mustSelectWALName(false, WALTypeWoodpecker, walEnable{true, true, true, true}), WALTypeWoodpecker) + assert.Equal(t, mustSelectWALName(true, message.WALNameRocksmq.String(), walEnable{true, true, true, true}), message.WALNameRocksmq) + assert.Equal(t, mustSelectWALName(true, message.WALNamePulsar.String(), walEnable{true, true, true, true}), message.WALNamePulsar) + assert.Equal(t, mustSelectWALName(true, message.WALNameKafka.String(), walEnable{true, true, true, true}), message.WALNameKafka) + assert.Equal(t, mustSelectWALName(true, message.WALNameWoodpecker.String(), walEnable{true, true, true, true}), message.WALNameWoodpecker) + assert.Panics(t, func() { mustSelectWALName(false, message.WALNameRocksmq.String(), walEnable{true, true, true, true}) }) + assert.Equal(t, mustSelectWALName(false, message.WALNamePulsar.String(), walEnable{true, true, true, true}), message.WALNamePulsar) + assert.Equal(t, mustSelectWALName(false, message.WALNameKafka.String(), walEnable{true, true, true, true}), message.WALNameKafka) + assert.Equal(t, mustSelectWALName(false, message.WALNameWoodpecker.String(), walEnable{true, true, true, true}), message.WALNameWoodpecker) } diff --git a/pkg/go.mod b/pkg/go.mod index 71eb43ef22..6682500bd0 100644 --- a/pkg/go.mod +++ b/pkg/go.mod @@ -21,7 +21,7 @@ require ( github.com/jolestar/go-commons-pool/v2 v2.1.2 github.com/json-iterator/go v1.1.12 github.com/klauspost/compress v1.17.9 - github.com/milvus-io/milvus-proto/go-api/v2 v2.6.1 + github.com/milvus-io/milvus-proto/go-api/v2 v2.6.2-0.20250901025546-3cddc9bb1357 github.com/minio/minio-go/v7 v7.0.73 github.com/panjf2000/ants/v2 v2.11.3 github.com/prometheus/client_golang v1.20.5 diff --git a/pkg/go.sum b/pkg/go.sum index d5107e8299..557b34b307 100644 --- a/pkg/go.sum +++ b/pkg/go.sum @@ -597,8 +597,8 @@ github.com/milvus-io/cgosymbolizer v0.0.0-20250318084424-114f4050c3a6 h1:YHMFI6L github.com/milvus-io/cgosymbolizer v0.0.0-20250318084424-114f4050c3a6/go.mod h1:DvXTE/K/RtHehxU8/GtDs4vFtfw64jJ3PaCnFri8CRg= github.com/milvus-io/gorocksdb v0.0.0-20220624081344-8c5f4212846b h1:TfeY0NxYxZzUfIfYe5qYDBzt4ZYRqzUjTR6CvUzjat8= github.com/milvus-io/gorocksdb v0.0.0-20220624081344-8c5f4212846b/go.mod h1:iwW+9cWfIzzDseEBCCeDSN5SD16Tidvy8cwQ7ZY8Qj4= -github.com/milvus-io/milvus-proto/go-api/v2 v2.6.1 h1:NLoSWXvlJD8t91G3CUsooXqYnm5nfsBngztQYYT58V0= -github.com/milvus-io/milvus-proto/go-api/v2 v2.6.1/go.mod h1:/6UT4zZl6awVeXLeE7UGDWZvXj3IWkRsh3mqsn0DiAs= +github.com/milvus-io/milvus-proto/go-api/v2 v2.6.2-0.20250901025546-3cddc9bb1357 h1:OYM9ylL42FTVL5kAHOZtsOPqzXq9Pn0/H1YLfXcS/e4= +github.com/milvus-io/milvus-proto/go-api/v2 v2.6.2-0.20250901025546-3cddc9bb1357/go.mod h1:/6UT4zZl6awVeXLeE7UGDWZvXj3IWkRsh3mqsn0DiAs= github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM= github.com/minio/minio-go/v7 v7.0.73 h1:qr2vi96Qm7kZ4v7LLebjte+MQh621fFWnv93p12htEo= diff --git a/pkg/metrics/cdc_metrics.go b/pkg/metrics/cdc_metrics.go new file mode 100644 index 0000000000..c34316f0c2 --- /dev/null +++ b/pkg/metrics/cdc_metrics.go @@ -0,0 +1,128 @@ +// Licensed to the LF AI & Data foundation under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The 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 metrics + +import ( + "github.com/prometheus/client_golang/prometheus" + + "github.com/milvus-io/milvus/pkg/v2/util/typeutil" +) + +const ( + // CDC metric names + CDCMetricReplicatedMessagesTotal = "replicated_messages_total" + CDCMetricReplicatedBytesTotal = "replicated_bytes_total" + CDCMetricReplicateEndToEndLatency = "replicate_end_to_end_latency" + CDCMetricReplicateLag = "replicate_lag" + CDCMetricStreamRPCConnections = "stream_rpc_connections" + CDCMetricStreamRPCReconnectTimes = "stream_rpc_reconnect_times" + + // CDC metric labels + CDCLabelTargetCluster = "target_cluster" + CDCLabelSourceChannelName = "source_channel_name" + CDCLabelTargetChannelName = "target_channel_name" + CDCLabelMsgType = msgTypeLabelName + CDCLabelConnectionStatus = "connection_status" + + // CDC metric values + CDCStatusConnected = "connected" + CDCStatusDisconnected = "disconnected" +) + +var CDCReplicatedMessagesTotal = prometheus.NewCounterVec( + prometheus.CounterOpts{ + Namespace: milvusNamespace, + Subsystem: typeutil.CDCRole, + Name: CDCMetricReplicatedMessagesTotal, + Help: "Total number of messages successfully forwarded by CDC", + }, []string{ + CDCLabelSourceChannelName, + CDCLabelTargetChannelName, + CDCLabelMsgType, + }, +) + +var CDCReplicatedBytesTotal = prometheus.NewCounterVec( + prometheus.CounterOpts{ + Namespace: milvusNamespace, + Subsystem: typeutil.CDCRole, + Name: CDCMetricReplicatedBytesTotal, + Help: "Total number of bytes of messages forwarded by CDC", + }, []string{ + CDCLabelSourceChannelName, + CDCLabelTargetChannelName, + CDCLabelMsgType, + }, +) + +var CDCReplicateEndToEndLatency = prometheus.NewHistogramVec( + prometheus.HistogramOpts{ + Namespace: milvusNamespace, + Subsystem: typeutil.CDCRole, + Name: CDCMetricReplicateEndToEndLatency, + Help: "End-to-end latency from a single message being read from Source WAL to being written to Target WAL and receiving an ack", + Buckets: buckets, + }, []string{ + CDCLabelSourceChannelName, + CDCLabelTargetChannelName, + }, +) + +// TODO: sheep +var CDCReplicateLag = prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Namespace: milvusNamespace, + Subsystem: typeutil.CDCRole, + Name: CDCMetricReplicateLag, + Help: "Lag between the latest message in Source and the latest message in Target", + }, []string{ + CDCLabelSourceChannelName, + CDCLabelTargetChannelName, + }, +) + +var CDCStreamRPCConnections = prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Namespace: milvusNamespace, + Subsystem: typeutil.CDCRole, + Name: CDCMetricStreamRPCConnections, + Help: "Stream RPC connections status between CDC and the target cluster", + }, []string{ + CDCLabelTargetCluster, + CDCLabelConnectionStatus, + }, +) + +var CDCStreamRPCReconnectTimes = prometheus.NewCounterVec( + prometheus.CounterOpts{ + Namespace: milvusNamespace, + Subsystem: typeutil.CDCRole, + Name: CDCMetricStreamRPCReconnectTimes, + Help: "Stream RPC reconnections times between CDC and the target cluster", + }, []string{ + CDCLabelTargetCluster, + }, +) + +func RegisterCDC(registry *prometheus.Registry) { + registry.MustRegister(CDCReplicatedMessagesTotal) + registry.MustRegister(CDCReplicatedBytesTotal) + registry.MustRegister(CDCReplicateEndToEndLatency) + registry.MustRegister(CDCReplicateLag) + registry.MustRegister(CDCStreamRPCConnections) + registry.MustRegister(CDCStreamRPCReconnectTimes) +} diff --git a/pkg/mocks/proto/mock_streamingpb/mock_StreamingCoordAssignmentServiceClient.go b/pkg/mocks/proto/mock_streamingpb/mock_StreamingCoordAssignmentServiceClient.go index ff8f4b2239..6d5395f79d 100644 --- a/pkg/mocks/proto/mock_streamingpb/mock_StreamingCoordAssignmentServiceClient.go +++ b/pkg/mocks/proto/mock_streamingpb/mock_StreamingCoordAssignmentServiceClient.go @@ -98,6 +98,80 @@ func (_c *MockStreamingCoordAssignmentServiceClient_AssignmentDiscover_Call) Run return _c } +// UpdateReplicateConfiguration provides a mock function with given fields: ctx, in, opts +func (_m *MockStreamingCoordAssignmentServiceClient) UpdateReplicateConfiguration(ctx context.Context, in *streamingpb.UpdateReplicateConfigurationRequest, opts ...grpc.CallOption) (*streamingpb.UpdateReplicateConfigurationResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for UpdateReplicateConfiguration") + } + + var r0 *streamingpb.UpdateReplicateConfigurationResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *streamingpb.UpdateReplicateConfigurationRequest, ...grpc.CallOption) (*streamingpb.UpdateReplicateConfigurationResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *streamingpb.UpdateReplicateConfigurationRequest, ...grpc.CallOption) *streamingpb.UpdateReplicateConfigurationResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*streamingpb.UpdateReplicateConfigurationResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *streamingpb.UpdateReplicateConfigurationRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockStreamingCoordAssignmentServiceClient_UpdateReplicateConfiguration_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateReplicateConfiguration' +type MockStreamingCoordAssignmentServiceClient_UpdateReplicateConfiguration_Call struct { + *mock.Call +} + +// UpdateReplicateConfiguration is a helper method to define mock.On call +// - ctx context.Context +// - in *streamingpb.UpdateReplicateConfigurationRequest +// - opts ...grpc.CallOption +func (_e *MockStreamingCoordAssignmentServiceClient_Expecter) UpdateReplicateConfiguration(ctx interface{}, in interface{}, opts ...interface{}) *MockStreamingCoordAssignmentServiceClient_UpdateReplicateConfiguration_Call { + return &MockStreamingCoordAssignmentServiceClient_UpdateReplicateConfiguration_Call{Call: _e.mock.On("UpdateReplicateConfiguration", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *MockStreamingCoordAssignmentServiceClient_UpdateReplicateConfiguration_Call) Run(run func(ctx context.Context, in *streamingpb.UpdateReplicateConfigurationRequest, opts ...grpc.CallOption)) *MockStreamingCoordAssignmentServiceClient_UpdateReplicateConfiguration_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*streamingpb.UpdateReplicateConfigurationRequest), variadicArgs...) + }) + return _c +} + +func (_c *MockStreamingCoordAssignmentServiceClient_UpdateReplicateConfiguration_Call) Return(_a0 *streamingpb.UpdateReplicateConfigurationResponse, _a1 error) *MockStreamingCoordAssignmentServiceClient_UpdateReplicateConfiguration_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockStreamingCoordAssignmentServiceClient_UpdateReplicateConfiguration_Call) RunAndReturn(run func(context.Context, *streamingpb.UpdateReplicateConfigurationRequest, ...grpc.CallOption) (*streamingpb.UpdateReplicateConfigurationResponse, error)) *MockStreamingCoordAssignmentServiceClient_UpdateReplicateConfiguration_Call { + _c.Call.Return(run) + return _c +} + // UpdateWALBalancePolicy provides a mock function with given fields: ctx, in, opts func (_m *MockStreamingCoordAssignmentServiceClient) UpdateWALBalancePolicy(ctx context.Context, in *streamingpb.UpdateWALBalancePolicyRequest, opts ...grpc.CallOption) (*streamingpb.UpdateWALBalancePolicyResponse, error) { _va := make([]interface{}, len(opts)) diff --git a/pkg/mocks/proto/mock_streamingpb/mock_StreamingNodeHandlerServiceClient.go b/pkg/mocks/proto/mock_streamingpb/mock_StreamingNodeHandlerServiceClient.go index 158374ae41..e67615b569 100644 --- a/pkg/mocks/proto/mock_streamingpb/mock_StreamingNodeHandlerServiceClient.go +++ b/pkg/mocks/proto/mock_streamingpb/mock_StreamingNodeHandlerServiceClient.go @@ -98,6 +98,80 @@ func (_c *MockStreamingNodeHandlerServiceClient_Consume_Call) RunAndReturn(run f return _c } +// GetReplicateCheckpoint provides a mock function with given fields: ctx, in, opts +func (_m *MockStreamingNodeHandlerServiceClient) GetReplicateCheckpoint(ctx context.Context, in *streamingpb.GetReplicateCheckpointRequest, opts ...grpc.CallOption) (*streamingpb.GetReplicateCheckpointResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for GetReplicateCheckpoint") + } + + var r0 *streamingpb.GetReplicateCheckpointResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *streamingpb.GetReplicateCheckpointRequest, ...grpc.CallOption) (*streamingpb.GetReplicateCheckpointResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *streamingpb.GetReplicateCheckpointRequest, ...grpc.CallOption) *streamingpb.GetReplicateCheckpointResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*streamingpb.GetReplicateCheckpointResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *streamingpb.GetReplicateCheckpointRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockStreamingNodeHandlerServiceClient_GetReplicateCheckpoint_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetReplicateCheckpoint' +type MockStreamingNodeHandlerServiceClient_GetReplicateCheckpoint_Call struct { + *mock.Call +} + +// GetReplicateCheckpoint is a helper method to define mock.On call +// - ctx context.Context +// - in *streamingpb.GetReplicateCheckpointRequest +// - opts ...grpc.CallOption +func (_e *MockStreamingNodeHandlerServiceClient_Expecter) GetReplicateCheckpoint(ctx interface{}, in interface{}, opts ...interface{}) *MockStreamingNodeHandlerServiceClient_GetReplicateCheckpoint_Call { + return &MockStreamingNodeHandlerServiceClient_GetReplicateCheckpoint_Call{Call: _e.mock.On("GetReplicateCheckpoint", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *MockStreamingNodeHandlerServiceClient_GetReplicateCheckpoint_Call) Run(run func(ctx context.Context, in *streamingpb.GetReplicateCheckpointRequest, opts ...grpc.CallOption)) *MockStreamingNodeHandlerServiceClient_GetReplicateCheckpoint_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*streamingpb.GetReplicateCheckpointRequest), variadicArgs...) + }) + return _c +} + +func (_c *MockStreamingNodeHandlerServiceClient_GetReplicateCheckpoint_Call) Return(_a0 *streamingpb.GetReplicateCheckpointResponse, _a1 error) *MockStreamingNodeHandlerServiceClient_GetReplicateCheckpoint_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockStreamingNodeHandlerServiceClient_GetReplicateCheckpoint_Call) RunAndReturn(run func(context.Context, *streamingpb.GetReplicateCheckpointRequest, ...grpc.CallOption) (*streamingpb.GetReplicateCheckpointResponse, error)) *MockStreamingNodeHandlerServiceClient_GetReplicateCheckpoint_Call { + _c.Call.Return(run) + return _c +} + // Produce provides a mock function with given fields: ctx, opts func (_m *MockStreamingNodeHandlerServiceClient) Produce(ctx context.Context, opts ...grpc.CallOption) (streamingpb.StreamingNodeHandlerService_ProduceClient, error) { _va := make([]interface{}, len(opts)) diff --git a/pkg/mocks/streaming/mock_walimpls/mock_OpenerBuilderImpls.go b/pkg/mocks/streaming/mock_walimpls/mock_OpenerBuilderImpls.go index bf091a466e..11eb7102f6 100644 --- a/pkg/mocks/streaming/mock_walimpls/mock_OpenerBuilderImpls.go +++ b/pkg/mocks/streaming/mock_walimpls/mock_OpenerBuilderImpls.go @@ -3,8 +3,10 @@ package mock_walimpls import ( - walimpls "github.com/milvus-io/milvus/pkg/v2/streaming/walimpls" + message "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" mock "github.com/stretchr/testify/mock" + + walimpls "github.com/milvus-io/milvus/pkg/v2/streaming/walimpls" ) // MockOpenerBuilderImpls is an autogenerated mock type for the OpenerBuilderImpls type @@ -78,18 +80,18 @@ func (_c *MockOpenerBuilderImpls_Build_Call) RunAndReturn(run func() (walimpls.O } // Name provides a mock function with no fields -func (_m *MockOpenerBuilderImpls) Name() string { +func (_m *MockOpenerBuilderImpls) Name() message.WALName { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for Name") } - var r0 string - if rf, ok := ret.Get(0).(func() string); ok { + var r0 message.WALName + if rf, ok := ret.Get(0).(func() message.WALName); ok { r0 = rf() } else { - r0 = ret.Get(0).(string) + r0 = ret.Get(0).(message.WALName) } return r0 @@ -112,12 +114,12 @@ func (_c *MockOpenerBuilderImpls_Name_Call) Run(run func()) *MockOpenerBuilderIm return _c } -func (_c *MockOpenerBuilderImpls_Name_Call) Return(_a0 string) *MockOpenerBuilderImpls_Name_Call { +func (_c *MockOpenerBuilderImpls_Name_Call) Return(_a0 message.WALName) *MockOpenerBuilderImpls_Name_Call { _c.Call.Return(_a0) return _c } -func (_c *MockOpenerBuilderImpls_Name_Call) RunAndReturn(run func() string) *MockOpenerBuilderImpls_Name_Call { +func (_c *MockOpenerBuilderImpls_Name_Call) RunAndReturn(run func() message.WALName) *MockOpenerBuilderImpls_Name_Call { _c.Call.Return(run) return _c } diff --git a/pkg/mocks/streaming/mock_walimpls/mock_WALImpls.go b/pkg/mocks/streaming/mock_walimpls/mock_WALImpls.go index 00c7af4e54..908d5e79a6 100644 --- a/pkg/mocks/streaming/mock_walimpls/mock_WALImpls.go +++ b/pkg/mocks/streaming/mock_walimpls/mock_WALImpls.go @@ -269,18 +269,18 @@ func (_c *MockWALImpls_Truncate_Call) RunAndReturn(run func(context.Context, mes } // WALName provides a mock function with no fields -func (_m *MockWALImpls) WALName() string { +func (_m *MockWALImpls) WALName() message.WALName { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for WALName") } - var r0 string - if rf, ok := ret.Get(0).(func() string); ok { + var r0 message.WALName + if rf, ok := ret.Get(0).(func() message.WALName); ok { r0 = rf() } else { - r0 = ret.Get(0).(string) + r0 = ret.Get(0).(message.WALName) } return r0 @@ -303,12 +303,12 @@ func (_c *MockWALImpls_WALName_Call) Run(run func()) *MockWALImpls_WALName_Call return _c } -func (_c *MockWALImpls_WALName_Call) Return(_a0 string) *MockWALImpls_WALName_Call { +func (_c *MockWALImpls_WALName_Call) Return(_a0 message.WALName) *MockWALImpls_WALName_Call { _c.Call.Return(_a0) return _c } -func (_c *MockWALImpls_WALName_Call) RunAndReturn(run func() string) *MockWALImpls_WALName_Call { +func (_c *MockWALImpls_WALName_Call) RunAndReturn(run func() message.WALName) *MockWALImpls_WALName_Call { _c.Call.Return(run) return _c } diff --git a/pkg/mocks/streaming/util/mock_message/mock_BroadcastMutableMessage.go b/pkg/mocks/streaming/util/mock_message/mock_BroadcastMutableMessage.go index f83ef10f8f..b7c905941a 100644 --- a/pkg/mocks/streaming/util/mock_message/mock_BroadcastMutableMessage.go +++ b/pkg/mocks/streaming/util/mock_message/mock_BroadcastMutableMessage.go @@ -483,6 +483,53 @@ func (_c *MockBroadcastMutableMessage_Properties_Call) RunAndReturn(run func() m return _c } +// ReplicateHeader provides a mock function with no fields +func (_m *MockBroadcastMutableMessage) ReplicateHeader() *message.ReplicateHeader { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for ReplicateHeader") + } + + var r0 *message.ReplicateHeader + if rf, ok := ret.Get(0).(func() *message.ReplicateHeader); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*message.ReplicateHeader) + } + } + + return r0 +} + +// MockBroadcastMutableMessage_ReplicateHeader_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ReplicateHeader' +type MockBroadcastMutableMessage_ReplicateHeader_Call struct { + *mock.Call +} + +// ReplicateHeader is a helper method to define mock.On call +func (_e *MockBroadcastMutableMessage_Expecter) ReplicateHeader() *MockBroadcastMutableMessage_ReplicateHeader_Call { + return &MockBroadcastMutableMessage_ReplicateHeader_Call{Call: _e.mock.On("ReplicateHeader")} +} + +func (_c *MockBroadcastMutableMessage_ReplicateHeader_Call) Run(run func()) *MockBroadcastMutableMessage_ReplicateHeader_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockBroadcastMutableMessage_ReplicateHeader_Call) Return(_a0 *message.ReplicateHeader) *MockBroadcastMutableMessage_ReplicateHeader_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockBroadcastMutableMessage_ReplicateHeader_Call) RunAndReturn(run func() *message.ReplicateHeader) *MockBroadcastMutableMessage_ReplicateHeader_Call { + _c.Call.Return(run) + return _c +} + // SplitIntoMutableMessage provides a mock function with no fields func (_m *MockBroadcastMutableMessage) SplitIntoMutableMessage() []message.MutableMessage { ret := _m.Called() diff --git a/pkg/mocks/streaming/util/mock_message/mock_ImmutableMessage.go b/pkg/mocks/streaming/util/mock_message/mock_ImmutableMessage.go index 4022bb96b7..5146f37421 100644 --- a/pkg/mocks/streaming/util/mock_message/mock_ImmutableMessage.go +++ b/pkg/mocks/streaming/util/mock_message/mock_ImmutableMessage.go @@ -3,9 +3,11 @@ package mock_message import ( - messagespb "github.com/milvus-io/milvus/pkg/v2/proto/messagespb" + commonpb "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" message "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" + messagespb "github.com/milvus-io/milvus/pkg/v2/proto/messagespb" + mock "github.com/stretchr/testify/mock" zapcore "go.uber.org/zap/zapcore" @@ -162,19 +164,19 @@ func (_c *MockImmutableMessage_EstimateSize_Call) RunAndReturn(run func() int) * } // IntoImmutableMessageProto provides a mock function with no fields -func (_m *MockImmutableMessage) IntoImmutableMessageProto() *messagespb.ImmutableMessage { +func (_m *MockImmutableMessage) IntoImmutableMessageProto() *commonpb.ImmutableMessage { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for IntoImmutableMessageProto") } - var r0 *messagespb.ImmutableMessage - if rf, ok := ret.Get(0).(func() *messagespb.ImmutableMessage); ok { + var r0 *commonpb.ImmutableMessage + if rf, ok := ret.Get(0).(func() *commonpb.ImmutableMessage); ok { r0 = rf() } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(*messagespb.ImmutableMessage) + r0 = ret.Get(0).(*commonpb.ImmutableMessage) } } @@ -198,12 +200,12 @@ func (_c *MockImmutableMessage_IntoImmutableMessageProto_Call) Run(run func()) * return _c } -func (_c *MockImmutableMessage_IntoImmutableMessageProto_Call) Return(_a0 *messagespb.ImmutableMessage) *MockImmutableMessage_IntoImmutableMessageProto_Call { +func (_c *MockImmutableMessage_IntoImmutableMessageProto_Call) Return(_a0 *commonpb.ImmutableMessage) *MockImmutableMessage_IntoImmutableMessageProto_Call { _c.Call.Return(_a0) return _c } -func (_c *MockImmutableMessage_IntoImmutableMessageProto_Call) RunAndReturn(run func() *messagespb.ImmutableMessage) *MockImmutableMessage_IntoImmutableMessageProto_Call { +func (_c *MockImmutableMessage_IntoImmutableMessageProto_Call) RunAndReturn(run func() *commonpb.ImmutableMessage) *MockImmutableMessage_IntoImmutableMessageProto_Call { _c.Call.Return(run) return _c } @@ -624,6 +626,53 @@ func (_c *MockImmutableMessage_Properties_Call) RunAndReturn(run func() message. return _c } +// ReplicateHeader provides a mock function with no fields +func (_m *MockImmutableMessage) ReplicateHeader() *message.ReplicateHeader { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for ReplicateHeader") + } + + var r0 *message.ReplicateHeader + if rf, ok := ret.Get(0).(func() *message.ReplicateHeader); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*message.ReplicateHeader) + } + } + + return r0 +} + +// MockImmutableMessage_ReplicateHeader_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ReplicateHeader' +type MockImmutableMessage_ReplicateHeader_Call struct { + *mock.Call +} + +// ReplicateHeader is a helper method to define mock.On call +func (_e *MockImmutableMessage_Expecter) ReplicateHeader() *MockImmutableMessage_ReplicateHeader_Call { + return &MockImmutableMessage_ReplicateHeader_Call{Call: _e.mock.On("ReplicateHeader")} +} + +func (_c *MockImmutableMessage_ReplicateHeader_Call) Run(run func()) *MockImmutableMessage_ReplicateHeader_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockImmutableMessage_ReplicateHeader_Call) Return(_a0 *message.ReplicateHeader) *MockImmutableMessage_ReplicateHeader_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockImmutableMessage_ReplicateHeader_Call) RunAndReturn(run func() *message.ReplicateHeader) *MockImmutableMessage_ReplicateHeader_Call { + _c.Call.Return(run) + return _c +} + // TimeTick provides a mock function with no fields func (_m *MockImmutableMessage) TimeTick() uint64 { ret := _m.Called() @@ -807,18 +856,18 @@ func (_c *MockImmutableMessage_Version_Call) RunAndReturn(run func() message.Ver } // WALName provides a mock function with no fields -func (_m *MockImmutableMessage) WALName() string { +func (_m *MockImmutableMessage) WALName() message.WALName { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for WALName") } - var r0 string - if rf, ok := ret.Get(0).(func() string); ok { + var r0 message.WALName + if rf, ok := ret.Get(0).(func() message.WALName); ok { r0 = rf() } else { - r0 = ret.Get(0).(string) + r0 = ret.Get(0).(message.WALName) } return r0 @@ -841,12 +890,12 @@ func (_c *MockImmutableMessage_WALName_Call) Run(run func()) *MockImmutableMessa return _c } -func (_c *MockImmutableMessage_WALName_Call) Return(_a0 string) *MockImmutableMessage_WALName_Call { +func (_c *MockImmutableMessage_WALName_Call) Return(_a0 message.WALName) *MockImmutableMessage_WALName_Call { _c.Call.Return(_a0) return _c } -func (_c *MockImmutableMessage_WALName_Call) RunAndReturn(run func() string) *MockImmutableMessage_WALName_Call { +func (_c *MockImmutableMessage_WALName_Call) RunAndReturn(run func() message.WALName) *MockImmutableMessage_WALName_Call { _c.Call.Return(run) return _c } diff --git a/pkg/mocks/streaming/util/mock_message/mock_ImmutableTxnMessage.go b/pkg/mocks/streaming/util/mock_message/mock_ImmutableTxnMessage.go index cae9070713..0e4d2b77c0 100644 --- a/pkg/mocks/streaming/util/mock_message/mock_ImmutableTxnMessage.go +++ b/pkg/mocks/streaming/util/mock_message/mock_ImmutableTxnMessage.go @@ -3,9 +3,11 @@ package mock_message import ( - messagespb "github.com/milvus-io/milvus/pkg/v2/proto/messagespb" + commonpb "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" message "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" + messagespb "github.com/milvus-io/milvus/pkg/v2/proto/messagespb" + mock "github.com/stretchr/testify/mock" zapcore "go.uber.org/zap/zapcore" @@ -256,19 +258,19 @@ func (_c *MockImmutableTxnMessage_EstimateSize_Call) RunAndReturn(run func() int } // IntoImmutableMessageProto provides a mock function with no fields -func (_m *MockImmutableTxnMessage) IntoImmutableMessageProto() *messagespb.ImmutableMessage { +func (_m *MockImmutableTxnMessage) IntoImmutableMessageProto() *commonpb.ImmutableMessage { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for IntoImmutableMessageProto") } - var r0 *messagespb.ImmutableMessage - if rf, ok := ret.Get(0).(func() *messagespb.ImmutableMessage); ok { + var r0 *commonpb.ImmutableMessage + if rf, ok := ret.Get(0).(func() *commonpb.ImmutableMessage); ok { r0 = rf() } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(*messagespb.ImmutableMessage) + r0 = ret.Get(0).(*commonpb.ImmutableMessage) } } @@ -292,12 +294,12 @@ func (_c *MockImmutableTxnMessage_IntoImmutableMessageProto_Call) Run(run func() return _c } -func (_c *MockImmutableTxnMessage_IntoImmutableMessageProto_Call) Return(_a0 *messagespb.ImmutableMessage) *MockImmutableTxnMessage_IntoImmutableMessageProto_Call { +func (_c *MockImmutableTxnMessage_IntoImmutableMessageProto_Call) Return(_a0 *commonpb.ImmutableMessage) *MockImmutableTxnMessage_IntoImmutableMessageProto_Call { _c.Call.Return(_a0) return _c } -func (_c *MockImmutableTxnMessage_IntoImmutableMessageProto_Call) RunAndReturn(run func() *messagespb.ImmutableMessage) *MockImmutableTxnMessage_IntoImmutableMessageProto_Call { +func (_c *MockImmutableTxnMessage_IntoImmutableMessageProto_Call) RunAndReturn(run func() *commonpb.ImmutableMessage) *MockImmutableTxnMessage_IntoImmutableMessageProto_Call { _c.Call.Return(run) return _c } @@ -764,6 +766,53 @@ func (_c *MockImmutableTxnMessage_RangeOver_Call) RunAndReturn(run func(func(mes return _c } +// ReplicateHeader provides a mock function with no fields +func (_m *MockImmutableTxnMessage) ReplicateHeader() *message.ReplicateHeader { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for ReplicateHeader") + } + + var r0 *message.ReplicateHeader + if rf, ok := ret.Get(0).(func() *message.ReplicateHeader); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*message.ReplicateHeader) + } + } + + return r0 +} + +// MockImmutableTxnMessage_ReplicateHeader_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ReplicateHeader' +type MockImmutableTxnMessage_ReplicateHeader_Call struct { + *mock.Call +} + +// ReplicateHeader is a helper method to define mock.On call +func (_e *MockImmutableTxnMessage_Expecter) ReplicateHeader() *MockImmutableTxnMessage_ReplicateHeader_Call { + return &MockImmutableTxnMessage_ReplicateHeader_Call{Call: _e.mock.On("ReplicateHeader")} +} + +func (_c *MockImmutableTxnMessage_ReplicateHeader_Call) Run(run func()) *MockImmutableTxnMessage_ReplicateHeader_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockImmutableTxnMessage_ReplicateHeader_Call) Return(_a0 *message.ReplicateHeader) *MockImmutableTxnMessage_ReplicateHeader_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockImmutableTxnMessage_ReplicateHeader_Call) RunAndReturn(run func() *message.ReplicateHeader) *MockImmutableTxnMessage_ReplicateHeader_Call { + _c.Call.Return(run) + return _c +} + // Size provides a mock function with no fields func (_m *MockImmutableTxnMessage) Size() int { ret := _m.Called() @@ -992,18 +1041,18 @@ func (_c *MockImmutableTxnMessage_Version_Call) RunAndReturn(run func() message. } // WALName provides a mock function with no fields -func (_m *MockImmutableTxnMessage) WALName() string { +func (_m *MockImmutableTxnMessage) WALName() message.WALName { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for WALName") } - var r0 string - if rf, ok := ret.Get(0).(func() string); ok { + var r0 message.WALName + if rf, ok := ret.Get(0).(func() message.WALName); ok { r0 = rf() } else { - r0 = ret.Get(0).(string) + r0 = ret.Get(0).(message.WALName) } return r0 @@ -1026,12 +1075,12 @@ func (_c *MockImmutableTxnMessage_WALName_Call) Run(run func()) *MockImmutableTx return _c } -func (_c *MockImmutableTxnMessage_WALName_Call) Return(_a0 string) *MockImmutableTxnMessage_WALName_Call { +func (_c *MockImmutableTxnMessage_WALName_Call) Return(_a0 message.WALName) *MockImmutableTxnMessage_WALName_Call { _c.Call.Return(_a0) return _c } -func (_c *MockImmutableTxnMessage_WALName_Call) RunAndReturn(run func() string) *MockImmutableTxnMessage_WALName_Call { +func (_c *MockImmutableTxnMessage_WALName_Call) RunAndReturn(run func() message.WALName) *MockImmutableTxnMessage_WALName_Call { _c.Call.Return(run) return _c } diff --git a/pkg/mocks/streaming/util/mock_message/mock_MessageID.go b/pkg/mocks/streaming/util/mock_message/mock_MessageID.go index b3fc0cd7ac..c986d78a70 100644 --- a/pkg/mocks/streaming/util/mock_message/mock_MessageID.go +++ b/pkg/mocks/streaming/util/mock_message/mock_MessageID.go @@ -3,7 +3,9 @@ package mock_message import ( + commonpb "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" message "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" + mock "github.com/stretchr/testify/mock" ) @@ -66,6 +68,53 @@ func (_c *MockMessageID_EQ_Call) RunAndReturn(run func(message.MessageID) bool) return _c } +// IntoProto provides a mock function with no fields +func (_m *MockMessageID) IntoProto() *commonpb.MessageID { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for IntoProto") + } + + var r0 *commonpb.MessageID + if rf, ok := ret.Get(0).(func() *commonpb.MessageID); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*commonpb.MessageID) + } + } + + return r0 +} + +// MockMessageID_IntoProto_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'IntoProto' +type MockMessageID_IntoProto_Call struct { + *mock.Call +} + +// IntoProto is a helper method to define mock.On call +func (_e *MockMessageID_Expecter) IntoProto() *MockMessageID_IntoProto_Call { + return &MockMessageID_IntoProto_Call{Call: _e.mock.On("IntoProto")} +} + +func (_c *MockMessageID_IntoProto_Call) Run(run func()) *MockMessageID_IntoProto_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockMessageID_IntoProto_Call) Return(_a0 *commonpb.MessageID) *MockMessageID_IntoProto_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockMessageID_IntoProto_Call) RunAndReturn(run func() *commonpb.MessageID) *MockMessageID_IntoProto_Call { + _c.Call.Return(run) + return _c +} + // LT provides a mock function with given fields: _a0 func (_m *MockMessageID) LT(_a0 message.MessageID) bool { ret := _m.Called(_a0) @@ -249,18 +298,18 @@ func (_c *MockMessageID_String_Call) RunAndReturn(run func() string) *MockMessag } // WALName provides a mock function with no fields -func (_m *MockMessageID) WALName() string { +func (_m *MockMessageID) WALName() message.WALName { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for WALName") } - var r0 string - if rf, ok := ret.Get(0).(func() string); ok { + var r0 message.WALName + if rf, ok := ret.Get(0).(func() message.WALName); ok { r0 = rf() } else { - r0 = ret.Get(0).(string) + r0 = ret.Get(0).(message.WALName) } return r0 @@ -283,12 +332,12 @@ func (_c *MockMessageID_WALName_Call) Run(run func()) *MockMessageID_WALName_Cal return _c } -func (_c *MockMessageID_WALName_Call) Return(_a0 string) *MockMessageID_WALName_Call { +func (_c *MockMessageID_WALName_Call) Return(_a0 message.WALName) *MockMessageID_WALName_Call { _c.Call.Return(_a0) return _c } -func (_c *MockMessageID_WALName_Call) RunAndReturn(run func() string) *MockMessageID_WALName_Call { +func (_c *MockMessageID_WALName_Call) RunAndReturn(run func() message.WALName) *MockMessageID_WALName_Call { _c.Call.Return(run) return _c } diff --git a/pkg/mocks/streaming/util/mock_message/mock_MutableMessage.go b/pkg/mocks/streaming/util/mock_message/mock_MutableMessage.go index 4e7e6275c2..8dab2e6afb 100644 --- a/pkg/mocks/streaming/util/mock_message/mock_MutableMessage.go +++ b/pkg/mocks/streaming/util/mock_message/mock_MutableMessage.go @@ -531,6 +531,53 @@ func (_c *MockMutableMessage_Properties_Call) RunAndReturn(run func() message.RP return _c } +// ReplicateHeader provides a mock function with no fields +func (_m *MockMutableMessage) ReplicateHeader() *message.ReplicateHeader { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for ReplicateHeader") + } + + var r0 *message.ReplicateHeader + if rf, ok := ret.Get(0).(func() *message.ReplicateHeader); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*message.ReplicateHeader) + } + } + + return r0 +} + +// MockMutableMessage_ReplicateHeader_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ReplicateHeader' +type MockMutableMessage_ReplicateHeader_Call struct { + *mock.Call +} + +// ReplicateHeader is a helper method to define mock.On call +func (_e *MockMutableMessage_Expecter) ReplicateHeader() *MockMutableMessage_ReplicateHeader_Call { + return &MockMutableMessage_ReplicateHeader_Call{Call: _e.mock.On("ReplicateHeader")} +} + +func (_c *MockMutableMessage_ReplicateHeader_Call) Run(run func()) *MockMutableMessage_ReplicateHeader_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockMutableMessage_ReplicateHeader_Call) Return(_a0 *message.ReplicateHeader) *MockMutableMessage_ReplicateHeader_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockMutableMessage_ReplicateHeader_Call) RunAndReturn(run func() *message.ReplicateHeader) *MockMutableMessage_ReplicateHeader_Call { + _c.Call.Return(run) + return _c +} + // TimeTick provides a mock function with no fields func (_m *MockMutableMessage) TimeTick() uint64 { ret := _m.Called() diff --git a/pkg/proto/messages.proto b/pkg/proto/messages.proto index 9302d81265..0de41aa7b9 100644 --- a/pkg/proto/messages.proto +++ b/pkg/proto/messages.proto @@ -4,27 +4,16 @@ package milvus.proto.messages; option go_package = "github.com/milvus-io/milvus/pkg/v2/proto/messagespb"; +import "common.proto"; import "schema.proto"; import "data_coord.proto"; // for SegmentLevel, but it's a basic type should not be in datacoord.proto. -// MessageID is the unique identifier of a message. -message MessageID { - string id = 1; -} - // Message is the basic unit of communication between publisher and consumer. message Message { bytes payload = 1; // message body map properties = 2; // message properties } -// ImmutableMessage is the message that can not be modified anymore. -message ImmutableMessage { - MessageID id = 1; - bytes payload = 2; // message body - map properties = 3; // message properties -} - // MessageType is the type of message. enum MessageType { Unknown = 0; @@ -40,6 +29,15 @@ enum MessageType { CreateSegment = 10; Import = 11; SchemaChange = 12; + + // PutReplicateConfig is used to put the replicate configuration to the current cluster. + // When the PutReplicateConfig message is received, the replication topology is changed. + // Maybe some cluster give up the leader role, no any other message will be received from this cluster. + // So leader will stop writing message into wal and stop replicating any message to the other cluster, + // and the follower will stop receiving any message from the old leader. + // New leader will start to write message into wal and start replicating message to the other cluster. + PutReplicateConfig = 800; + // begin transaction message is only used for transaction, once a begin // transaction message is received, all messages combined with the // transaction message cannot be consumed until a CommitTxn message @@ -188,6 +186,15 @@ message DropPartitionMessageHeader { int64 partition_id = 2; } +// PutReplicateConfigMessageHeader is the header of put replicate configuration message. +message PutReplicateConfigMessageHeader { + common.ReplicateConfiguration replicate_configuration = 1; +} + +// PutReplicateConfigMessageBody is the body of put replicate configuration message. +message PutReplicateConfigMessageBody { +} + // BeginTxnMessageHeader is the header of begin transaction message. // Just do nothing now. // Add Channel info here to implement cross pchannel transaction. @@ -276,6 +283,15 @@ message BroadcastHeader { // And the user can watch the resource key to known when the resource is released. } +// ReplicateHeader is the header of replicate message. +message ReplicateHeader { + string cluster_id = 1; // the cluster id of source cluster + common.MessageID message_id = 2; // the message id of replicate msg from source cluster + common.MessageID last_confirmed_message_id = 3; // the last confirmed message id of replicate msg from source cluster + uint64 time_tick = 4; // the time tick of replicate msg from source cluster + string vchannel = 5; // the vchannel of replicate msg from source cluster +} + // ResourceDomain is the domain of resource hold. enum ResourceDomain { ResourceDomainUnknown = 0; // should never be used. diff --git a/pkg/proto/messagespb/messages.pb.go b/pkg/proto/messagespb/messages.pb.go index e5ecead3a9..2d5c851556 100644 --- a/pkg/proto/messagespb/messages.pb.go +++ b/pkg/proto/messagespb/messages.pb.go @@ -7,6 +7,7 @@ package messagespb import ( + commonpb "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" schemapb "github.com/milvus-io/milvus-proto/go-api/v2/schemapb" datapb "github.com/milvus-io/milvus/pkg/v2/proto/datapb" protoreflect "google.golang.org/protobuf/reflect/protoreflect" @@ -39,6 +40,13 @@ const ( MessageType_CreateSegment MessageType = 10 MessageType_Import MessageType = 11 MessageType_SchemaChange MessageType = 12 + // PutReplicateConfig is used to put the replicate configuration to the current cluster. + // When the PutReplicateConfig message is received, the replication topology is changed. + // Maybe some cluster give up the leader role, no any other message will be received from this cluster. + // So leader will stop writing message into wal and stop replicating any message to the other cluster, + // and the follower will stop receiving any message from the old leader. + // New leader will start to write message into wal and start replicating message to the other cluster. + MessageType_PutReplicateConfig MessageType = 800 // begin transaction message is only used for transaction, once a begin // transaction message is received, all messages combined with the // transaction message cannot be consumed until a CommitTxn message @@ -78,29 +86,31 @@ var ( 10: "CreateSegment", 11: "Import", 12: "SchemaChange", + 800: "PutReplicateConfig", 900: "BeginTxn", 901: "CommitTxn", 902: "RollbackTxn", 999: "Txn", } MessageType_value = map[string]int32{ - "Unknown": 0, - "TimeTick": 1, - "Insert": 2, - "Delete": 3, - "Flush": 4, - "CreateCollection": 5, - "DropCollection": 6, - "CreatePartition": 7, - "DropPartition": 8, - "ManualFlush": 9, - "CreateSegment": 10, - "Import": 11, - "SchemaChange": 12, - "BeginTxn": 900, - "CommitTxn": 901, - "RollbackTxn": 902, - "Txn": 999, + "Unknown": 0, + "TimeTick": 1, + "Insert": 2, + "Delete": 3, + "Flush": 4, + "CreateCollection": 5, + "DropCollection": 6, + "CreatePartition": 7, + "DropPartition": 8, + "ManualFlush": 9, + "CreateSegment": 10, + "Import": 11, + "SchemaChange": 12, + "PutReplicateConfig": 800, + "BeginTxn": 900, + "CommitTxn": 901, + "RollbackTxn": 902, + "Txn": 999, } ) @@ -245,54 +255,6 @@ func (ResourceDomain) EnumDescriptor() ([]byte, []int) { return file_messages_proto_rawDescGZIP(), []int{2} } -// MessageID is the unique identifier of a message. -type MessageID struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` -} - -func (x *MessageID) Reset() { - *x = MessageID{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *MessageID) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*MessageID) ProtoMessage() {} - -func (x *MessageID) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use MessageID.ProtoReflect.Descriptor instead. -func (*MessageID) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{0} -} - -func (x *MessageID) GetId() string { - if x != nil { - return x.Id - } - return "" -} - // Message is the basic unit of communication between publisher and consumer. type Message struct { state protoimpl.MessageState @@ -306,7 +268,7 @@ type Message struct { func (x *Message) Reset() { *x = Message{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[1] + mi := &file_messages_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -319,7 +281,7 @@ func (x *Message) String() string { func (*Message) ProtoMessage() {} func (x *Message) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[1] + mi := &file_messages_proto_msgTypes[0] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -332,7 +294,7 @@ func (x *Message) ProtoReflect() protoreflect.Message { // Deprecated: Use Message.ProtoReflect.Descriptor instead. func (*Message) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{1} + return file_messages_proto_rawDescGZIP(), []int{0} } func (x *Message) GetPayload() []byte { @@ -349,70 +311,6 @@ func (x *Message) GetProperties() map[string]string { return nil } -// ImmutableMessage is the message that can not be modified anymore. -type ImmutableMessage struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Id *MessageID `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Payload []byte `protobuf:"bytes,2,opt,name=payload,proto3" json:"payload,omitempty"` // message body - Properties map[string]string `protobuf:"bytes,3,rep,name=properties,proto3" json:"properties,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` // message properties -} - -func (x *ImmutableMessage) Reset() { - *x = ImmutableMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ImmutableMessage) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ImmutableMessage) ProtoMessage() {} - -func (x *ImmutableMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ImmutableMessage.ProtoReflect.Descriptor instead. -func (*ImmutableMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{2} -} - -func (x *ImmutableMessage) GetId() *MessageID { - if x != nil { - return x.Id - } - return nil -} - -func (x *ImmutableMessage) GetPayload() []byte { - if x != nil { - return x.Payload - } - return nil -} - -func (x *ImmutableMessage) GetProperties() map[string]string { - if x != nil { - return x.Properties - } - return nil -} - // FlushMessageBody is the body of flush message. type FlushMessageBody struct { state protoimpl.MessageState @@ -423,7 +321,7 @@ type FlushMessageBody struct { func (x *FlushMessageBody) Reset() { *x = FlushMessageBody{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[3] + mi := &file_messages_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -436,7 +334,7 @@ func (x *FlushMessageBody) String() string { func (*FlushMessageBody) ProtoMessage() {} func (x *FlushMessageBody) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[3] + mi := &file_messages_proto_msgTypes[1] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -449,7 +347,7 @@ func (x *FlushMessageBody) ProtoReflect() protoreflect.Message { // Deprecated: Use FlushMessageBody.ProtoReflect.Descriptor instead. func (*FlushMessageBody) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{3} + return file_messages_proto_rawDescGZIP(), []int{1} } // ManualFlushMessageBody is the body of manual flush message. @@ -462,7 +360,7 @@ type ManualFlushMessageBody struct { func (x *ManualFlushMessageBody) Reset() { *x = ManualFlushMessageBody{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[4] + mi := &file_messages_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -475,7 +373,7 @@ func (x *ManualFlushMessageBody) String() string { func (*ManualFlushMessageBody) ProtoMessage() {} func (x *ManualFlushMessageBody) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[4] + mi := &file_messages_proto_msgTypes[2] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -488,7 +386,7 @@ func (x *ManualFlushMessageBody) ProtoReflect() protoreflect.Message { // Deprecated: Use ManualFlushMessageBody.ProtoReflect.Descriptor instead. func (*ManualFlushMessageBody) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{4} + return file_messages_proto_rawDescGZIP(), []int{2} } // CreateSegmentMessageBody is the body of create segment message. @@ -501,7 +399,7 @@ type CreateSegmentMessageBody struct { func (x *CreateSegmentMessageBody) Reset() { *x = CreateSegmentMessageBody{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[5] + mi := &file_messages_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -514,7 +412,7 @@ func (x *CreateSegmentMessageBody) String() string { func (*CreateSegmentMessageBody) ProtoMessage() {} func (x *CreateSegmentMessageBody) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[5] + mi := &file_messages_proto_msgTypes[3] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -527,7 +425,7 @@ func (x *CreateSegmentMessageBody) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateSegmentMessageBody.ProtoReflect.Descriptor instead. func (*CreateSegmentMessageBody) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{5} + return file_messages_proto_rawDescGZIP(), []int{3} } // BeginTxnMessageBody is the body of begin transaction message. @@ -541,7 +439,7 @@ type BeginTxnMessageBody struct { func (x *BeginTxnMessageBody) Reset() { *x = BeginTxnMessageBody{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[6] + mi := &file_messages_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -554,7 +452,7 @@ func (x *BeginTxnMessageBody) String() string { func (*BeginTxnMessageBody) ProtoMessage() {} func (x *BeginTxnMessageBody) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[6] + mi := &file_messages_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -567,7 +465,7 @@ func (x *BeginTxnMessageBody) ProtoReflect() protoreflect.Message { // Deprecated: Use BeginTxnMessageBody.ProtoReflect.Descriptor instead. func (*BeginTxnMessageBody) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{6} + return file_messages_proto_rawDescGZIP(), []int{4} } // CommitTxnMessageBody is the body of commit transaction message. @@ -581,7 +479,7 @@ type CommitTxnMessageBody struct { func (x *CommitTxnMessageBody) Reset() { *x = CommitTxnMessageBody{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[7] + mi := &file_messages_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -594,7 +492,7 @@ func (x *CommitTxnMessageBody) String() string { func (*CommitTxnMessageBody) ProtoMessage() {} func (x *CommitTxnMessageBody) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[7] + mi := &file_messages_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -607,7 +505,7 @@ func (x *CommitTxnMessageBody) ProtoReflect() protoreflect.Message { // Deprecated: Use CommitTxnMessageBody.ProtoReflect.Descriptor instead. func (*CommitTxnMessageBody) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{7} + return file_messages_proto_rawDescGZIP(), []int{5} } // RollbackTxnMessageBody is the body of rollback transaction message. @@ -621,7 +519,7 @@ type RollbackTxnMessageBody struct { func (x *RollbackTxnMessageBody) Reset() { *x = RollbackTxnMessageBody{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[8] + mi := &file_messages_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -634,7 +532,7 @@ func (x *RollbackTxnMessageBody) String() string { func (*RollbackTxnMessageBody) ProtoMessage() {} func (x *RollbackTxnMessageBody) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[8] + mi := &file_messages_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -647,7 +545,7 @@ func (x *RollbackTxnMessageBody) ProtoReflect() protoreflect.Message { // Deprecated: Use RollbackTxnMessageBody.ProtoReflect.Descriptor instead. func (*RollbackTxnMessageBody) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{8} + return file_messages_proto_rawDescGZIP(), []int{6} } // TxnMessageBody is the body of transaction message. @@ -666,7 +564,7 @@ type TxnMessageBody struct { func (x *TxnMessageBody) Reset() { *x = TxnMessageBody{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[9] + mi := &file_messages_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -679,7 +577,7 @@ func (x *TxnMessageBody) String() string { func (*TxnMessageBody) ProtoMessage() {} func (x *TxnMessageBody) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[9] + mi := &file_messages_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -692,7 +590,7 @@ func (x *TxnMessageBody) ProtoReflect() protoreflect.Message { // Deprecated: Use TxnMessageBody.ProtoReflect.Descriptor instead. func (*TxnMessageBody) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{9} + return file_messages_proto_rawDescGZIP(), []int{7} } func (x *TxnMessageBody) GetMessages() []*Message { @@ -712,7 +610,7 @@ type TimeTickMessageHeader struct { func (x *TimeTickMessageHeader) Reset() { *x = TimeTickMessageHeader{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[10] + mi := &file_messages_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -725,7 +623,7 @@ func (x *TimeTickMessageHeader) String() string { func (*TimeTickMessageHeader) ProtoMessage() {} func (x *TimeTickMessageHeader) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[10] + mi := &file_messages_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -738,7 +636,7 @@ func (x *TimeTickMessageHeader) ProtoReflect() protoreflect.Message { // Deprecated: Use TimeTickMessageHeader.ProtoReflect.Descriptor instead. func (*TimeTickMessageHeader) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{10} + return file_messages_proto_rawDescGZIP(), []int{8} } // InsertMessageHeader is the header of insert message. @@ -754,7 +652,7 @@ type InsertMessageHeader struct { func (x *InsertMessageHeader) Reset() { *x = InsertMessageHeader{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[11] + mi := &file_messages_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -767,7 +665,7 @@ func (x *InsertMessageHeader) String() string { func (*InsertMessageHeader) ProtoMessage() {} func (x *InsertMessageHeader) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[11] + mi := &file_messages_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -780,7 +678,7 @@ func (x *InsertMessageHeader) ProtoReflect() protoreflect.Message { // Deprecated: Use InsertMessageHeader.ProtoReflect.Descriptor instead. func (*InsertMessageHeader) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{11} + return file_messages_proto_rawDescGZIP(), []int{9} } func (x *InsertMessageHeader) GetCollectionId() int64 { @@ -812,7 +710,7 @@ type PartitionSegmentAssignment struct { func (x *PartitionSegmentAssignment) Reset() { *x = PartitionSegmentAssignment{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[12] + mi := &file_messages_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -825,7 +723,7 @@ func (x *PartitionSegmentAssignment) String() string { func (*PartitionSegmentAssignment) ProtoMessage() {} func (x *PartitionSegmentAssignment) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[12] + mi := &file_messages_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -838,7 +736,7 @@ func (x *PartitionSegmentAssignment) ProtoReflect() protoreflect.Message { // Deprecated: Use PartitionSegmentAssignment.ProtoReflect.Descriptor instead. func (*PartitionSegmentAssignment) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{12} + return file_messages_proto_rawDescGZIP(), []int{10} } func (x *PartitionSegmentAssignment) GetPartitionId() int64 { @@ -881,7 +779,7 @@ type SegmentAssignment struct { func (x *SegmentAssignment) Reset() { *x = SegmentAssignment{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[13] + mi := &file_messages_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -894,7 +792,7 @@ func (x *SegmentAssignment) String() string { func (*SegmentAssignment) ProtoMessage() {} func (x *SegmentAssignment) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[13] + mi := &file_messages_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -907,7 +805,7 @@ func (x *SegmentAssignment) ProtoReflect() protoreflect.Message { // Deprecated: Use SegmentAssignment.ProtoReflect.Descriptor instead. func (*SegmentAssignment) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{13} + return file_messages_proto_rawDescGZIP(), []int{11} } func (x *SegmentAssignment) GetSegmentId() int64 { @@ -930,7 +828,7 @@ type DeleteMessageHeader struct { func (x *DeleteMessageHeader) Reset() { *x = DeleteMessageHeader{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[14] + mi := &file_messages_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -943,7 +841,7 @@ func (x *DeleteMessageHeader) String() string { func (*DeleteMessageHeader) ProtoMessage() {} func (x *DeleteMessageHeader) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[14] + mi := &file_messages_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -956,7 +854,7 @@ func (x *DeleteMessageHeader) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteMessageHeader.ProtoReflect.Descriptor instead. func (*DeleteMessageHeader) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{14} + return file_messages_proto_rawDescGZIP(), []int{12} } func (x *DeleteMessageHeader) GetCollectionId() int64 { @@ -987,7 +885,7 @@ type FlushMessageHeader struct { func (x *FlushMessageHeader) Reset() { *x = FlushMessageHeader{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[15] + mi := &file_messages_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1000,7 +898,7 @@ func (x *FlushMessageHeader) String() string { func (*FlushMessageHeader) ProtoMessage() {} func (x *FlushMessageHeader) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[15] + mi := &file_messages_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1013,7 +911,7 @@ func (x *FlushMessageHeader) ProtoReflect() protoreflect.Message { // Deprecated: Use FlushMessageHeader.ProtoReflect.Descriptor instead. func (*FlushMessageHeader) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{15} + return file_messages_proto_rawDescGZIP(), []int{13} } func (x *FlushMessageHeader) GetCollectionId() int64 { @@ -1055,7 +953,7 @@ type CreateSegmentMessageHeader struct { func (x *CreateSegmentMessageHeader) Reset() { *x = CreateSegmentMessageHeader{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[16] + mi := &file_messages_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1068,7 +966,7 @@ func (x *CreateSegmentMessageHeader) String() string { func (*CreateSegmentMessageHeader) ProtoMessage() {} func (x *CreateSegmentMessageHeader) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[16] + mi := &file_messages_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1081,7 +979,7 @@ func (x *CreateSegmentMessageHeader) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateSegmentMessageHeader.ProtoReflect.Descriptor instead. func (*CreateSegmentMessageHeader) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{16} + return file_messages_proto_rawDescGZIP(), []int{14} } func (x *CreateSegmentMessageHeader) GetCollectionId() int64 { @@ -1146,7 +1044,7 @@ type ManualFlushMessageHeader struct { func (x *ManualFlushMessageHeader) Reset() { *x = ManualFlushMessageHeader{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[17] + mi := &file_messages_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1159,7 +1057,7 @@ func (x *ManualFlushMessageHeader) String() string { func (*ManualFlushMessageHeader) ProtoMessage() {} func (x *ManualFlushMessageHeader) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[17] + mi := &file_messages_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1172,7 +1070,7 @@ func (x *ManualFlushMessageHeader) ProtoReflect() protoreflect.Message { // Deprecated: Use ManualFlushMessageHeader.ProtoReflect.Descriptor instead. func (*ManualFlushMessageHeader) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{17} + return file_messages_proto_rawDescGZIP(), []int{15} } func (x *ManualFlushMessageHeader) GetCollectionId() int64 { @@ -1209,7 +1107,7 @@ type CreateCollectionMessageHeader struct { func (x *CreateCollectionMessageHeader) Reset() { *x = CreateCollectionMessageHeader{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[18] + mi := &file_messages_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1222,7 +1120,7 @@ func (x *CreateCollectionMessageHeader) String() string { func (*CreateCollectionMessageHeader) ProtoMessage() {} func (x *CreateCollectionMessageHeader) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[18] + mi := &file_messages_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1235,7 +1133,7 @@ func (x *CreateCollectionMessageHeader) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateCollectionMessageHeader.ProtoReflect.Descriptor instead. func (*CreateCollectionMessageHeader) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{18} + return file_messages_proto_rawDescGZIP(), []int{16} } func (x *CreateCollectionMessageHeader) GetCollectionId() int64 { @@ -1264,7 +1162,7 @@ type DropCollectionMessageHeader struct { func (x *DropCollectionMessageHeader) Reset() { *x = DropCollectionMessageHeader{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[19] + mi := &file_messages_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1277,7 +1175,7 @@ func (x *DropCollectionMessageHeader) String() string { func (*DropCollectionMessageHeader) ProtoMessage() {} func (x *DropCollectionMessageHeader) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[19] + mi := &file_messages_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1290,7 +1188,7 @@ func (x *DropCollectionMessageHeader) ProtoReflect() protoreflect.Message { // Deprecated: Use DropCollectionMessageHeader.ProtoReflect.Descriptor instead. func (*DropCollectionMessageHeader) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{19} + return file_messages_proto_rawDescGZIP(), []int{17} } func (x *DropCollectionMessageHeader) GetCollectionId() int64 { @@ -1313,7 +1211,7 @@ type CreatePartitionMessageHeader struct { func (x *CreatePartitionMessageHeader) Reset() { *x = CreatePartitionMessageHeader{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[20] + mi := &file_messages_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1326,7 +1224,7 @@ func (x *CreatePartitionMessageHeader) String() string { func (*CreatePartitionMessageHeader) ProtoMessage() {} func (x *CreatePartitionMessageHeader) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[20] + mi := &file_messages_proto_msgTypes[18] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1339,7 +1237,7 @@ func (x *CreatePartitionMessageHeader) ProtoReflect() protoreflect.Message { // Deprecated: Use CreatePartitionMessageHeader.ProtoReflect.Descriptor instead. func (*CreatePartitionMessageHeader) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{20} + return file_messages_proto_rawDescGZIP(), []int{18} } func (x *CreatePartitionMessageHeader) GetCollectionId() int64 { @@ -1369,7 +1267,7 @@ type DropPartitionMessageHeader struct { func (x *DropPartitionMessageHeader) Reset() { *x = DropPartitionMessageHeader{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[21] + mi := &file_messages_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1382,7 +1280,7 @@ func (x *DropPartitionMessageHeader) String() string { func (*DropPartitionMessageHeader) ProtoMessage() {} func (x *DropPartitionMessageHeader) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[21] + mi := &file_messages_proto_msgTypes[19] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1395,7 +1293,7 @@ func (x *DropPartitionMessageHeader) ProtoReflect() protoreflect.Message { // Deprecated: Use DropPartitionMessageHeader.ProtoReflect.Descriptor instead. func (*DropPartitionMessageHeader) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{21} + return file_messages_proto_rawDescGZIP(), []int{19} } func (x *DropPartitionMessageHeader) GetCollectionId() int64 { @@ -1412,6 +1310,93 @@ func (x *DropPartitionMessageHeader) GetPartitionId() int64 { return 0 } +// PutReplicateConfigMessageHeader is the header of put replicate configuration message. +type PutReplicateConfigMessageHeader struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ReplicateConfiguration *commonpb.ReplicateConfiguration `protobuf:"bytes,1,opt,name=replicate_configuration,json=replicateConfiguration,proto3" json:"replicate_configuration,omitempty"` +} + +func (x *PutReplicateConfigMessageHeader) Reset() { + *x = PutReplicateConfigMessageHeader{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PutReplicateConfigMessageHeader) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PutReplicateConfigMessageHeader) ProtoMessage() {} + +func (x *PutReplicateConfigMessageHeader) ProtoReflect() protoreflect.Message { + mi := &file_messages_proto_msgTypes[20] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PutReplicateConfigMessageHeader.ProtoReflect.Descriptor instead. +func (*PutReplicateConfigMessageHeader) Descriptor() ([]byte, []int) { + return file_messages_proto_rawDescGZIP(), []int{20} +} + +func (x *PutReplicateConfigMessageHeader) GetReplicateConfiguration() *commonpb.ReplicateConfiguration { + if x != nil { + return x.ReplicateConfiguration + } + return nil +} + +// PutReplicateConfigMessageBody is the body of put replicate configuration message. +type PutReplicateConfigMessageBody struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *PutReplicateConfigMessageBody) Reset() { + *x = PutReplicateConfigMessageBody{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PutReplicateConfigMessageBody) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PutReplicateConfigMessageBody) ProtoMessage() {} + +func (x *PutReplicateConfigMessageBody) ProtoReflect() protoreflect.Message { + mi := &file_messages_proto_msgTypes[21] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PutReplicateConfigMessageBody.ProtoReflect.Descriptor instead. +func (*PutReplicateConfigMessageBody) Descriptor() ([]byte, []int) { + return file_messages_proto_rawDescGZIP(), []int{21} +} + // BeginTxnMessageHeader is the header of begin transaction message. // Just do nothing now. // Add Channel info here to implement cross pchannel transaction. @@ -1956,6 +1941,86 @@ func (x *BroadcastHeader) GetResourceKeys() []*ResourceKey { return nil } +// ReplicateHeader is the header of replicate message. +type ReplicateHeader struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ClusterId string `protobuf:"bytes,1,opt,name=cluster_id,json=clusterId,proto3" json:"cluster_id,omitempty"` // the cluster id of source cluster + MessageId *commonpb.MessageID `protobuf:"bytes,2,opt,name=message_id,json=messageId,proto3" json:"message_id,omitempty"` // the message id of replicate msg from source cluster + LastConfirmedMessageId *commonpb.MessageID `protobuf:"bytes,3,opt,name=last_confirmed_message_id,json=lastConfirmedMessageId,proto3" json:"last_confirmed_message_id,omitempty"` // the last confirmed message id of replicate msg from source cluster + TimeTick uint64 `protobuf:"varint,4,opt,name=time_tick,json=timeTick,proto3" json:"time_tick,omitempty"` // the time tick of replicate msg from source cluster + Vchannel string `protobuf:"bytes,5,opt,name=vchannel,proto3" json:"vchannel,omitempty"` // the vchannel of replicate msg from source cluster +} + +func (x *ReplicateHeader) Reset() { + *x = ReplicateHeader{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_proto_msgTypes[33] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ReplicateHeader) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReplicateHeader) ProtoMessage() {} + +func (x *ReplicateHeader) ProtoReflect() protoreflect.Message { + mi := &file_messages_proto_msgTypes[33] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ReplicateHeader.ProtoReflect.Descriptor instead. +func (*ReplicateHeader) Descriptor() ([]byte, []int) { + return file_messages_proto_rawDescGZIP(), []int{33} +} + +func (x *ReplicateHeader) GetClusterId() string { + if x != nil { + return x.ClusterId + } + return "" +} + +func (x *ReplicateHeader) GetMessageId() *commonpb.MessageID { + if x != nil { + return x.MessageId + } + return nil +} + +func (x *ReplicateHeader) GetLastConfirmedMessageId() *commonpb.MessageID { + if x != nil { + return x.LastConfirmedMessageId + } + return nil +} + +func (x *ReplicateHeader) GetTimeTick() uint64 { + if x != nil { + return x.TimeTick + } + return 0 +} + +func (x *ReplicateHeader) GetVchannel() string { + if x != nil { + return x.Vchannel + } + return "" +} + // ResourceKey is the key for resource hold. // It's used to implement the resource acquirition mechanism for broadcast message. // The key should be a unique identifier of the resource for different domain. @@ -1971,7 +2036,7 @@ type ResourceKey struct { func (x *ResourceKey) Reset() { *x = ResourceKey{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[33] + mi := &file_messages_proto_msgTypes[34] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1984,7 +2049,7 @@ func (x *ResourceKey) String() string { func (*ResourceKey) ProtoMessage() {} func (x *ResourceKey) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[33] + mi := &file_messages_proto_msgTypes[34] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1997,7 +2062,7 @@ func (x *ResourceKey) ProtoReflect() protoreflect.Message { // Deprecated: Use ResourceKey.ProtoReflect.Descriptor instead. func (*ResourceKey) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{33} + return file_messages_proto_rawDescGZIP(), []int{34} } func (x *ResourceKey) GetDomain() ResourceDomain { @@ -2029,7 +2094,7 @@ type CipherHeader struct { func (x *CipherHeader) Reset() { *x = CipherHeader{} if protoimpl.UnsafeEnabled { - mi := &file_messages_proto_msgTypes[34] + mi := &file_messages_proto_msgTypes[35] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2042,7 +2107,7 @@ func (x *CipherHeader) String() string { func (*CipherHeader) ProtoMessage() {} func (x *CipherHeader) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[34] + mi := &file_messages_proto_msgTypes[35] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2055,7 +2120,7 @@ func (x *CipherHeader) ProtoReflect() protoreflect.Message { // Deprecated: Use CipherHeader.ProtoReflect.Descriptor instead. func (*CipherHeader) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{34} + return file_messages_proto_rawDescGZIP(), []int{35} } func (x *CipherHeader) GetEzId() int64 { @@ -2091,248 +2156,260 @@ var File_messages_proto protoreflect.FileDescriptor var file_messages_proto_rawDesc = []byte{ 0x0a, 0x0e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x15, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x1a, 0x0c, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x10, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x63, 0x6f, 0x6f, 0x72, - 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x1b, 0x0a, 0x09, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x49, 0x44, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x02, 0x69, 0x64, 0x22, 0xb2, 0x01, 0x0a, 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x4e, 0x0a, 0x0a, 0x70, 0x72, - 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, - 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x50, - 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, - 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x1a, 0x3d, 0x0a, 0x0f, 0x50, 0x72, - 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, - 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, - 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xf6, 0x01, 0x0a, 0x10, 0x49, 0x6d, - 0x6d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x30, - 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x6d, 0x69, 0x6c, - 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x73, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x44, 0x52, 0x02, 0x69, 0x64, - 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x57, 0x0a, 0x0a, 0x70, 0x72, - 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x37, - 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x49, 0x6d, 0x6d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, - 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, - 0x69, 0x65, 0x73, 0x1a, 0x3d, 0x0a, 0x0f, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, - 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, - 0x38, 0x01, 0x22, 0x12, 0x0a, 0x10, 0x46, 0x6c, 0x75, 0x73, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x42, 0x6f, 0x64, 0x79, 0x22, 0x18, 0x0a, 0x16, 0x4d, 0x61, 0x6e, 0x75, 0x61, 0x6c, - 0x46, 0x6c, 0x75, 0x73, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x6f, 0x64, 0x79, - 0x22, 0x1a, 0x0a, 0x18, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, - 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x6f, 0x64, 0x79, 0x22, 0x15, 0x0a, 0x13, - 0x42, 0x65, 0x67, 0x69, 0x6e, 0x54, 0x78, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, - 0x6f, 0x64, 0x79, 0x22, 0x16, 0x0a, 0x14, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x54, 0x78, 0x6e, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x6f, 0x64, 0x79, 0x22, 0x18, 0x0a, 0x16, 0x52, - 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x54, 0x78, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x42, 0x6f, 0x64, 0x79, 0x22, 0x4c, 0x0a, 0x0e, 0x54, 0x78, 0x6e, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x3a, 0x0a, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6d, 0x69, 0x6c, 0x76, - 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x73, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x73, 0x22, 0x17, 0x0a, 0x15, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x22, 0x8d, 0x01, 0x0a, - 0x13, 0x49, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x65, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x1a, 0x0c, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x0c, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x1a, 0x10, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb2, 0x01, 0x0a, 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x4e, 0x0a, 0x0a, 0x70, + 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x2e, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, + 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, + 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x1a, 0x3d, 0x0a, 0x0f, 0x50, + 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, + 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, + 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x12, 0x0a, 0x10, 0x46, 0x6c, + 0x75, 0x73, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x6f, 0x64, 0x79, 0x22, 0x18, + 0x0a, 0x16, 0x4d, 0x61, 0x6e, 0x75, 0x61, 0x6c, 0x46, 0x6c, 0x75, 0x73, 0x68, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x42, 0x6f, 0x64, 0x79, 0x22, 0x1a, 0x0a, 0x18, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x42, 0x6f, 0x64, 0x79, 0x22, 0x15, 0x0a, 0x13, 0x42, 0x65, 0x67, 0x69, 0x6e, 0x54, 0x78, 0x6e, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x6f, 0x64, 0x79, 0x22, 0x16, 0x0a, 0x14, 0x43, + 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x54, 0x78, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, + 0x6f, 0x64, 0x79, 0x22, 0x18, 0x0a, 0x16, 0x52, 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x54, + 0x78, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x6f, 0x64, 0x79, 0x22, 0x4c, 0x0a, + 0x0e, 0x54, 0x78, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x6f, 0x64, 0x79, 0x12, + 0x3a, 0x0a, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x1e, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x52, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x22, 0x17, 0x0a, 0x15, 0x54, + 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x65, + 0x61, 0x64, 0x65, 0x72, 0x22, 0x8d, 0x01, 0x0a, 0x13, 0x49, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x23, 0x0a, 0x0d, + 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, + 0x64, 0x12, 0x51, 0x0a, 0x0a, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x50, 0x61, + 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x41, 0x73, + 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x0a, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xcd, 0x01, 0x0a, 0x1a, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, + 0x6f, 0x6e, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, + 0x65, 0x6e, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, + 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x6f, 0x77, 0x73, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x72, 0x6f, 0x77, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x62, 0x69, + 0x6e, 0x61, 0x72, 0x79, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x0a, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x57, 0x0a, 0x12, 0x73, + 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x61, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, + 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, + 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, + 0x74, 0x52, 0x11, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, + 0x6d, 0x65, 0x6e, 0x74, 0x22, 0x32, 0x0a, 0x11, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x41, + 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x67, + 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x73, + 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x22, 0x4e, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, + 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x6f, 0x77, 0x73, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x04, 0x72, 0x6f, 0x77, 0x73, 0x22, 0x7b, 0x0a, 0x12, 0x46, 0x6c, 0x75, 0x73, + 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x23, + 0x0a, 0x0d, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, + 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, + 0x74, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x73, 0x65, 0x67, 0x6d, + 0x65, 0x6e, 0x74, 0x49, 0x64, 0x22, 0xa8, 0x02, 0x0a, 0x1a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, 0x6f, 0x6c, - 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x51, 0x0a, 0x0a, 0x70, 0x61, 0x72, - 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x31, 0x2e, - 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x53, - 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, - 0x52, 0x0a, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xcd, 0x01, 0x0a, - 0x1a, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, - 0x74, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, - 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x12, - 0x0a, 0x04, 0x72, 0x6f, 0x77, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x72, 0x6f, - 0x77, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x5f, 0x73, 0x69, 0x7a, - 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x53, - 0x69, 0x7a, 0x65, 0x12, 0x57, 0x0a, 0x12, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x61, - 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x28, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x41, - 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x11, 0x73, 0x65, 0x67, 0x6d, 0x65, - 0x6e, 0x74, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x22, 0x32, 0x0a, 0x11, - 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, - 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x64, - 0x22, 0x4e, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x61, 0x72, + 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, + 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x09, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x27, 0x0a, 0x0f, 0x73, + 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x56, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x28, 0x0a, 0x10, 0x6d, 0x61, 0x78, 0x5f, 0x73, 0x65, 0x67, 0x6d, + 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, + 0x6d, 0x61, 0x78, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x19, + 0x0a, 0x08, 0x6d, 0x61, 0x78, 0x5f, 0x72, 0x6f, 0x77, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x07, 0x6d, 0x61, 0x78, 0x52, 0x6f, 0x77, 0x73, 0x12, 0x35, 0x0a, 0x05, 0x6c, 0x65, 0x76, + 0x65, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1f, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, + 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x53, 0x65, 0x67, + 0x6d, 0x65, 0x6e, 0x74, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, + 0x22, 0x7b, 0x0a, 0x18, 0x4d, 0x61, 0x6e, 0x75, 0x61, 0x6c, 0x46, 0x6c, 0x75, 0x73, 0x68, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x23, 0x0a, 0x0d, + 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, + 0x64, 0x12, 0x19, 0x0a, 0x08, 0x66, 0x6c, 0x75, 0x73, 0x68, 0x5f, 0x74, 0x73, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x07, 0x66, 0x6c, 0x75, 0x73, 0x68, 0x54, 0x73, 0x12, 0x1f, 0x0a, 0x0b, + 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, + 0x03, 0x52, 0x0a, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x73, 0x22, 0x69, 0x0a, + 0x1d, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x23, + 0x0a, 0x0d, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x69, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x03, 0x52, 0x0c, 0x70, 0x61, 0x72, 0x74, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x22, 0x42, 0x0a, 0x1b, 0x44, 0x72, 0x6f, 0x70, + 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, - 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, - 0x72, 0x6f, 0x77, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x72, 0x6f, 0x77, 0x73, - 0x22, 0x7b, 0x0a, 0x12, 0x46, 0x6c, 0x75, 0x73, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, - 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x70, - 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1d, - 0x0a, 0x0a, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x09, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x22, 0xa8, 0x02, - 0x0a, 0x1a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x4d, + 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0x66, 0x0a, 0x1c, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, - 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x5f, - 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, - 0x74, 0x49, 0x64, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x76, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x73, 0x74, - 0x6f, 0x72, 0x61, 0x67, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x28, 0x0a, 0x10, - 0x6d, 0x61, 0x78, 0x5f, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x6d, 0x61, 0x78, 0x53, 0x65, 0x67, 0x6d, 0x65, - 0x6e, 0x74, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x6d, 0x61, 0x78, 0x5f, 0x72, 0x6f, - 0x77, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x6d, 0x61, 0x78, 0x52, 0x6f, 0x77, - 0x73, 0x12, 0x35, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, - 0x32, 0x1f, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, - 0x64, 0x61, 0x74, 0x61, 0x2e, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x4c, 0x65, 0x76, 0x65, - 0x6c, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x22, 0x7b, 0x0a, 0x18, 0x4d, 0x61, 0x6e, 0x75, - 0x61, 0x6c, 0x46, 0x6c, 0x75, 0x73, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x65, - 0x61, 0x64, 0x65, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, 0x6f, 0x6c, - 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x66, 0x6c, 0x75, - 0x73, 0x68, 0x5f, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x66, 0x6c, 0x75, - 0x73, 0x68, 0x54, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x5f, - 0x69, 0x64, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x03, 0x52, 0x0a, 0x73, 0x65, 0x67, 0x6d, 0x65, - 0x6e, 0x74, 0x49, 0x64, 0x73, 0x22, 0x69, 0x0a, 0x1d, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, - 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, - 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x70, - 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, - 0x28, 0x03, 0x52, 0x0c, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, - 0x22, 0x42, 0x0a, 0x1b, 0x44, 0x72, 0x6f, 0x70, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, - 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x49, 0x64, 0x22, 0x66, 0x0a, 0x1c, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x61, - 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x65, - 0x61, 0x64, 0x65, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, 0x6f, 0x6c, - 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x61, 0x72, - 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0x64, 0x0a, 0x1a, - 0x44, 0x72, 0x6f, 0x70, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, - 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, - 0x21, 0x0a, 0x0c, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, - 0x49, 0x64, 0x22, 0x4e, 0x0a, 0x15, 0x42, 0x65, 0x67, 0x69, 0x6e, 0x54, 0x78, 0x6e, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x35, 0x0a, 0x16, 0x6b, - 0x65, 0x65, 0x70, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x5f, 0x6d, 0x69, 0x6c, 0x6c, 0x69, 0x73, 0x65, - 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x15, 0x6b, 0x65, 0x65, - 0x70, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x4d, 0x69, 0x6c, 0x6c, 0x69, 0x73, 0x65, 0x63, 0x6f, 0x6e, - 0x64, 0x73, 0x22, 0x18, 0x0a, 0x16, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x54, 0x78, 0x6e, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x22, 0x1a, 0x0a, 0x18, - 0x52, 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x54, 0x78, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x22, 0x12, 0x0a, 0x10, 0x54, 0x78, 0x6e, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x22, 0x15, 0x0a, 0x13, - 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x65, 0x61, - 0x64, 0x65, 0x72, 0x22, 0x70, 0x0a, 0x19, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x43, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, - 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x2e, 0x0a, 0x13, 0x66, 0x6c, 0x75, 0x73, 0x68, 0x65, 0x64, - 0x5f, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, - 0x28, 0x03, 0x52, 0x11, 0x66, 0x6c, 0x75, 0x73, 0x68, 0x65, 0x64, 0x53, 0x65, 0x67, 0x6d, 0x65, - 0x6e, 0x74, 0x49, 0x64, 0x73, 0x22, 0x58, 0x0a, 0x17, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x43, - 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x6f, 0x64, 0x79, - 0x12, 0x3d, 0x0a, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x25, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, - 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x22, - 0x3b, 0x0a, 0x18, 0x4d, 0x61, 0x6e, 0x75, 0x61, 0x6c, 0x46, 0x6c, 0x75, 0x73, 0x68, 0x45, 0x78, - 0x74, 0x72, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, - 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x03, - 0x52, 0x0a, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x73, 0x22, 0x5a, 0x0a, 0x0a, - 0x54, 0x78, 0x6e, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x15, 0x0a, 0x06, 0x74, 0x78, - 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x74, 0x78, 0x6e, 0x49, - 0x64, 0x12, 0x35, 0x0a, 0x16, 0x6b, 0x65, 0x65, 0x70, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x5f, 0x6d, - 0x69, 0x6c, 0x6c, 0x69, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x15, 0x6b, 0x65, 0x65, 0x70, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x4d, 0x69, 0x6c, 0x6c, - 0x69, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x22, 0xc4, 0x01, 0x0a, 0x10, 0x52, 0x4d, 0x51, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x4c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x12, 0x18, 0x0a, - 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, - 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x57, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, - 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x6d, 0x69, - 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x73, 0x2e, 0x52, 0x4d, 0x51, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x4c, 0x61, - 0x79, 0x6f, 0x75, 0x74, 0x2e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, - 0x1a, 0x3d, 0x0a, 0x0f, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x45, 0x6e, - 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, - 0x9b, 0x01, 0x0a, 0x0f, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x48, 0x65, 0x61, - 0x64, 0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x62, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, - 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x62, 0x72, 0x6f, 0x61, 0x64, - 0x63, 0x61, 0x73, 0x74, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x76, 0x63, 0x68, 0x61, 0x6e, 0x6e, - 0x65, 0x6c, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x76, 0x63, 0x68, 0x61, 0x6e, - 0x6e, 0x65, 0x6c, 0x73, 0x12, 0x47, 0x0a, 0x0d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x6d, 0x69, - 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x73, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4b, 0x65, 0x79, 0x52, - 0x0c, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4b, 0x65, 0x79, 0x73, 0x22, 0x5e, 0x0a, - 0x0b, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x3d, 0x0a, 0x06, - 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x25, 0x2e, 0x6d, - 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x73, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, 0x6f, 0x6d, - 0x61, 0x69, 0x6e, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x6b, - 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22, 0x88, 0x01, - 0x0a, 0x0c, 0x43, 0x69, 0x70, 0x68, 0x65, 0x72, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x13, - 0x0a, 0x05, 0x65, 0x7a, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x65, - 0x7a, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, - 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x61, 0x66, 0x65, - 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x73, 0x61, 0x66, 0x65, - 0x4b, 0x65, 0x79, 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x62, - 0x79, 0x74, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x70, 0x61, 0x79, 0x6c, - 0x6f, 0x61, 0x64, 0x42, 0x79, 0x74, 0x65, 0x73, 0x2a, 0x9a, 0x02, 0x0a, 0x0b, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x6e, 0x6b, 0x6e, - 0x6f, 0x77, 0x6e, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, - 0x6b, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x49, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x10, 0x02, 0x12, - 0x0a, 0x0a, 0x06, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x10, 0x03, 0x12, 0x09, 0x0a, 0x05, 0x46, - 0x6c, 0x75, 0x73, 0x68, 0x10, 0x04, 0x12, 0x14, 0x0a, 0x10, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x10, 0x05, 0x12, 0x12, 0x0a, 0x0e, - 0x44, 0x72, 0x6f, 0x70, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x10, 0x06, - 0x12, 0x13, 0x0a, 0x0f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, - 0x69, 0x6f, 0x6e, 0x10, 0x07, 0x12, 0x11, 0x0a, 0x0d, 0x44, 0x72, 0x6f, 0x70, 0x50, 0x61, 0x72, - 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x10, 0x08, 0x12, 0x0f, 0x0a, 0x0b, 0x4d, 0x61, 0x6e, 0x75, - 0x61, 0x6c, 0x46, 0x6c, 0x75, 0x73, 0x68, 0x10, 0x09, 0x12, 0x11, 0x0a, 0x0d, 0x43, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x10, 0x0a, 0x12, 0x0a, 0x0a, 0x06, - 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x10, 0x0b, 0x12, 0x10, 0x0a, 0x0c, 0x53, 0x63, 0x68, 0x65, - 0x6d, 0x61, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x10, 0x0c, 0x12, 0x0d, 0x0a, 0x08, 0x42, 0x65, - 0x67, 0x69, 0x6e, 0x54, 0x78, 0x6e, 0x10, 0x84, 0x07, 0x12, 0x0e, 0x0a, 0x09, 0x43, 0x6f, 0x6d, - 0x6d, 0x69, 0x74, 0x54, 0x78, 0x6e, 0x10, 0x85, 0x07, 0x12, 0x10, 0x0a, 0x0b, 0x52, 0x6f, 0x6c, - 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x54, 0x78, 0x6e, 0x10, 0x86, 0x07, 0x12, 0x08, 0x0a, 0x03, 0x54, - 0x78, 0x6e, 0x10, 0xe7, 0x07, 0x2a, 0x74, 0x0a, 0x08, 0x54, 0x78, 0x6e, 0x53, 0x74, 0x61, 0x74, - 0x65, 0x12, 0x0e, 0x0a, 0x0a, 0x54, 0x78, 0x6e, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x10, - 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x54, 0x78, 0x6e, 0x49, 0x6e, 0x46, 0x6c, 0x69, 0x67, 0x68, 0x74, - 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x54, 0x78, 0x6e, 0x4f, 0x6e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, - 0x74, 0x10, 0x02, 0x12, 0x10, 0x0a, 0x0c, 0x54, 0x78, 0x6e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, - 0x74, 0x65, 0x64, 0x10, 0x03, 0x12, 0x11, 0x0a, 0x0d, 0x54, 0x78, 0x6e, 0x4f, 0x6e, 0x52, 0x6f, - 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x10, 0x04, 0x12, 0x11, 0x0a, 0x0d, 0x54, 0x78, 0x6e, 0x52, - 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x64, 0x10, 0x05, 0x2a, 0x6c, 0x0a, 0x0e, 0x52, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x19, 0x0a, - 0x15, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x55, - 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x10, 0x00, 0x12, 0x1d, 0x0a, 0x19, 0x52, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, - 0x4a, 0x6f, 0x62, 0x49, 0x44, 0x10, 0x01, 0x12, 0x20, 0x0a, 0x1c, 0x52, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x10, 0x02, 0x42, 0x35, 0x5a, 0x33, 0x67, 0x69, 0x74, - 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2d, 0x69, - 0x6f, 0x2f, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x76, 0x32, 0x2f, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x70, 0x62, - 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6f, 0x6e, 0x49, 0x64, 0x22, 0x64, 0x0a, 0x1a, 0x44, 0x72, 0x6f, 0x70, 0x50, 0x61, 0x72, 0x74, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x65, 0x61, 0x64, + 0x65, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x61, 0x72, 0x74, 0x69, + 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x70, + 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0x87, 0x01, 0x0a, 0x1f, 0x50, + 0x75, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x64, + 0x0a, 0x17, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x2b, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, + 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x16, 0x72, 0x65, + 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x1f, 0x0a, 0x1d, 0x50, 0x75, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x69, + 0x63, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x42, 0x6f, 0x64, 0x79, 0x22, 0x4e, 0x0a, 0x15, 0x42, 0x65, 0x67, 0x69, 0x6e, 0x54, 0x78, + 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x35, + 0x0a, 0x16, 0x6b, 0x65, 0x65, 0x70, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x5f, 0x6d, 0x69, 0x6c, 0x6c, + 0x69, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x15, + 0x6b, 0x65, 0x65, 0x70, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x4d, 0x69, 0x6c, 0x6c, 0x69, 0x73, 0x65, + 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x22, 0x18, 0x0a, 0x16, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x54, + 0x78, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x22, + 0x1a, 0x0a, 0x18, 0x52, 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x54, 0x78, 0x6e, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x22, 0x12, 0x0a, 0x10, 0x54, + 0x78, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x22, + 0x15, 0x0a, 0x13, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x22, 0x70, 0x0a, 0x19, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, + 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x48, 0x65, 0x61, + 0x64, 0x65, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x2e, 0x0a, 0x13, 0x66, 0x6c, 0x75, 0x73, + 0x68, 0x65, 0x64, 0x5f, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x73, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x03, 0x52, 0x11, 0x66, 0x6c, 0x75, 0x73, 0x68, 0x65, 0x64, 0x53, 0x65, + 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x73, 0x22, 0x58, 0x0a, 0x17, 0x53, 0x63, 0x68, 0x65, + 0x6d, 0x61, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, + 0x6f, 0x64, 0x79, 0x12, 0x3d, 0x0a, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x06, 0x73, 0x63, 0x68, 0x65, + 0x6d, 0x61, 0x22, 0x3b, 0x0a, 0x18, 0x4d, 0x61, 0x6e, 0x75, 0x61, 0x6c, 0x46, 0x6c, 0x75, 0x73, + 0x68, 0x45, 0x78, 0x74, 0x72, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, + 0x0a, 0x0b, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x03, 0x52, 0x0a, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x73, 0x22, + 0x5a, 0x0a, 0x0a, 0x54, 0x78, 0x6e, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x15, 0x0a, + 0x06, 0x74, 0x78, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x74, + 0x78, 0x6e, 0x49, 0x64, 0x12, 0x35, 0x0a, 0x16, 0x6b, 0x65, 0x65, 0x70, 0x61, 0x6c, 0x69, 0x76, + 0x65, 0x5f, 0x6d, 0x69, 0x6c, 0x6c, 0x69, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x15, 0x6b, 0x65, 0x65, 0x70, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x4d, + 0x69, 0x6c, 0x6c, 0x69, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x22, 0xc4, 0x01, 0x0a, 0x10, + 0x52, 0x4d, 0x51, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x4c, 0x61, 0x79, 0x6f, 0x75, 0x74, + 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x57, 0x0a, 0x0a, 0x70, 0x72, + 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x37, + 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x52, 0x4d, 0x51, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x4c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x2e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, + 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, + 0x69, 0x65, 0x73, 0x1a, 0x3d, 0x0a, 0x0f, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, + 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, + 0x38, 0x01, 0x22, 0x9b, 0x01, 0x0a, 0x0f, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, + 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x62, 0x72, 0x6f, 0x61, 0x64, 0x63, + 0x61, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x62, 0x72, + 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x76, 0x63, 0x68, + 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x76, 0x63, + 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x12, 0x47, 0x0a, 0x0d, 0x52, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, + 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4b, + 0x65, 0x79, 0x52, 0x0c, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4b, 0x65, 0x79, 0x73, + 0x22, 0x83, 0x02, 0x0a, 0x0f, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x48, 0x65, + 0x61, 0x64, 0x65, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, + 0x72, 0x49, 0x64, 0x12, 0x3d, 0x0a, 0x0a, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x69, + 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x44, 0x52, 0x09, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x49, 0x64, 0x12, 0x59, 0x0a, 0x19, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x72, 0x6d, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x69, 0x64, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x49, 0x44, 0x52, 0x16, 0x6c, 0x61, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x72, 0x6d, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x64, 0x12, 0x1b, 0x0a, + 0x09, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x69, 0x63, 0x6b, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x08, 0x74, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x12, 0x1a, 0x0a, 0x08, 0x76, 0x63, + 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x76, 0x63, + 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x22, 0x5e, 0x0a, 0x0b, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x3d, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x25, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x52, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x06, 0x64, 0x6f, + 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22, 0x88, 0x01, 0x0a, 0x0c, 0x43, 0x69, 0x70, 0x68, 0x65, + 0x72, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x13, 0x0a, 0x05, 0x65, 0x7a, 0x5f, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x65, 0x7a, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, + 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, + 0x64, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x61, 0x66, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x07, 0x73, 0x61, 0x66, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x23, 0x0a, 0x0d, + 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x0c, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x42, 0x79, 0x74, 0x65, + 0x73, 0x2a, 0xb3, 0x02, 0x0a, 0x0b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, + 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x10, 0x00, 0x12, 0x0c, + 0x0a, 0x08, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, + 0x49, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x10, 0x03, 0x12, 0x09, 0x0a, 0x05, 0x46, 0x6c, 0x75, 0x73, 0x68, 0x10, 0x04, 0x12, + 0x14, 0x0a, 0x10, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x10, 0x05, 0x12, 0x12, 0x0a, 0x0e, 0x44, 0x72, 0x6f, 0x70, 0x43, 0x6f, 0x6c, + 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x10, 0x06, 0x12, 0x13, 0x0a, 0x0f, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x10, 0x07, 0x12, 0x11, + 0x0a, 0x0d, 0x44, 0x72, 0x6f, 0x70, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x10, + 0x08, 0x12, 0x0f, 0x0a, 0x0b, 0x4d, 0x61, 0x6e, 0x75, 0x61, 0x6c, 0x46, 0x6c, 0x75, 0x73, 0x68, + 0x10, 0x09, 0x12, 0x11, 0x0a, 0x0d, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, 0x67, 0x6d, + 0x65, 0x6e, 0x74, 0x10, 0x0a, 0x12, 0x0a, 0x0a, 0x06, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x10, + 0x0b, 0x12, 0x10, 0x0a, 0x0c, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x43, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x10, 0x0c, 0x12, 0x17, 0x0a, 0x12, 0x50, 0x75, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, + 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x10, 0xa0, 0x06, 0x12, 0x0d, 0x0a, 0x08, + 0x42, 0x65, 0x67, 0x69, 0x6e, 0x54, 0x78, 0x6e, 0x10, 0x84, 0x07, 0x12, 0x0e, 0x0a, 0x09, 0x43, + 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x54, 0x78, 0x6e, 0x10, 0x85, 0x07, 0x12, 0x10, 0x0a, 0x0b, 0x52, + 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x54, 0x78, 0x6e, 0x10, 0x86, 0x07, 0x12, 0x08, 0x0a, + 0x03, 0x54, 0x78, 0x6e, 0x10, 0xe7, 0x07, 0x2a, 0x74, 0x0a, 0x08, 0x54, 0x78, 0x6e, 0x53, 0x74, + 0x61, 0x74, 0x65, 0x12, 0x0e, 0x0a, 0x0a, 0x54, 0x78, 0x6e, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, + 0x6e, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x54, 0x78, 0x6e, 0x49, 0x6e, 0x46, 0x6c, 0x69, 0x67, + 0x68, 0x74, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x54, 0x78, 0x6e, 0x4f, 0x6e, 0x43, 0x6f, 0x6d, + 0x6d, 0x69, 0x74, 0x10, 0x02, 0x12, 0x10, 0x0a, 0x0c, 0x54, 0x78, 0x6e, 0x43, 0x6f, 0x6d, 0x6d, + 0x69, 0x74, 0x74, 0x65, 0x64, 0x10, 0x03, 0x12, 0x11, 0x0a, 0x0d, 0x54, 0x78, 0x6e, 0x4f, 0x6e, + 0x52, 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x10, 0x04, 0x12, 0x11, 0x0a, 0x0d, 0x54, 0x78, + 0x6e, 0x52, 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x64, 0x10, 0x05, 0x2a, 0x6c, 0x0a, + 0x0e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, + 0x19, 0x0a, 0x15, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, 0x6f, 0x6d, 0x61, 0x69, + 0x6e, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x10, 0x00, 0x12, 0x1d, 0x0a, 0x19, 0x52, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x49, 0x6d, 0x70, 0x6f, + 0x72, 0x74, 0x4a, 0x6f, 0x62, 0x49, 0x44, 0x10, 0x01, 0x12, 0x20, 0x0a, 0x1c, 0x52, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x43, 0x6f, 0x6c, 0x6c, 0x65, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x10, 0x02, 0x42, 0x35, 0x5a, 0x33, 0x67, + 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, + 0x2d, 0x69, 0x6f, 0x2f, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x76, + 0x32, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, + 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -2350,67 +2427,70 @@ func file_messages_proto_rawDescGZIP() []byte { var file_messages_proto_enumTypes = make([]protoimpl.EnumInfo, 3) var file_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 38) var file_messages_proto_goTypes = []interface{}{ - (MessageType)(0), // 0: milvus.proto.messages.MessageType - (TxnState)(0), // 1: milvus.proto.messages.TxnState - (ResourceDomain)(0), // 2: milvus.proto.messages.ResourceDomain - (*MessageID)(nil), // 3: milvus.proto.messages.MessageID - (*Message)(nil), // 4: milvus.proto.messages.Message - (*ImmutableMessage)(nil), // 5: milvus.proto.messages.ImmutableMessage - (*FlushMessageBody)(nil), // 6: milvus.proto.messages.FlushMessageBody - (*ManualFlushMessageBody)(nil), // 7: milvus.proto.messages.ManualFlushMessageBody - (*CreateSegmentMessageBody)(nil), // 8: milvus.proto.messages.CreateSegmentMessageBody - (*BeginTxnMessageBody)(nil), // 9: milvus.proto.messages.BeginTxnMessageBody - (*CommitTxnMessageBody)(nil), // 10: milvus.proto.messages.CommitTxnMessageBody - (*RollbackTxnMessageBody)(nil), // 11: milvus.proto.messages.RollbackTxnMessageBody - (*TxnMessageBody)(nil), // 12: milvus.proto.messages.TxnMessageBody - (*TimeTickMessageHeader)(nil), // 13: milvus.proto.messages.TimeTickMessageHeader - (*InsertMessageHeader)(nil), // 14: milvus.proto.messages.InsertMessageHeader - (*PartitionSegmentAssignment)(nil), // 15: milvus.proto.messages.PartitionSegmentAssignment - (*SegmentAssignment)(nil), // 16: milvus.proto.messages.SegmentAssignment - (*DeleteMessageHeader)(nil), // 17: milvus.proto.messages.DeleteMessageHeader - (*FlushMessageHeader)(nil), // 18: milvus.proto.messages.FlushMessageHeader - (*CreateSegmentMessageHeader)(nil), // 19: milvus.proto.messages.CreateSegmentMessageHeader - (*ManualFlushMessageHeader)(nil), // 20: milvus.proto.messages.ManualFlushMessageHeader - (*CreateCollectionMessageHeader)(nil), // 21: milvus.proto.messages.CreateCollectionMessageHeader - (*DropCollectionMessageHeader)(nil), // 22: milvus.proto.messages.DropCollectionMessageHeader - (*CreatePartitionMessageHeader)(nil), // 23: milvus.proto.messages.CreatePartitionMessageHeader - (*DropPartitionMessageHeader)(nil), // 24: milvus.proto.messages.DropPartitionMessageHeader - (*BeginTxnMessageHeader)(nil), // 25: milvus.proto.messages.BeginTxnMessageHeader - (*CommitTxnMessageHeader)(nil), // 26: milvus.proto.messages.CommitTxnMessageHeader - (*RollbackTxnMessageHeader)(nil), // 27: milvus.proto.messages.RollbackTxnMessageHeader - (*TxnMessageHeader)(nil), // 28: milvus.proto.messages.TxnMessageHeader - (*ImportMessageHeader)(nil), // 29: milvus.proto.messages.ImportMessageHeader - (*SchemaChangeMessageHeader)(nil), // 30: milvus.proto.messages.SchemaChangeMessageHeader - (*SchemaChangeMessageBody)(nil), // 31: milvus.proto.messages.SchemaChangeMessageBody - (*ManualFlushExtraResponse)(nil), // 32: milvus.proto.messages.ManualFlushExtraResponse - (*TxnContext)(nil), // 33: milvus.proto.messages.TxnContext - (*RMQMessageLayout)(nil), // 34: milvus.proto.messages.RMQMessageLayout - (*BroadcastHeader)(nil), // 35: milvus.proto.messages.BroadcastHeader - (*ResourceKey)(nil), // 36: milvus.proto.messages.ResourceKey - (*CipherHeader)(nil), // 37: milvus.proto.messages.CipherHeader - nil, // 38: milvus.proto.messages.Message.PropertiesEntry - nil, // 39: milvus.proto.messages.ImmutableMessage.PropertiesEntry - nil, // 40: milvus.proto.messages.RMQMessageLayout.PropertiesEntry - (datapb.SegmentLevel)(0), // 41: milvus.proto.data.SegmentLevel - (*schemapb.CollectionSchema)(nil), // 42: milvus.proto.schema.CollectionSchema + (MessageType)(0), // 0: milvus.proto.messages.MessageType + (TxnState)(0), // 1: milvus.proto.messages.TxnState + (ResourceDomain)(0), // 2: milvus.proto.messages.ResourceDomain + (*Message)(nil), // 3: milvus.proto.messages.Message + (*FlushMessageBody)(nil), // 4: milvus.proto.messages.FlushMessageBody + (*ManualFlushMessageBody)(nil), // 5: milvus.proto.messages.ManualFlushMessageBody + (*CreateSegmentMessageBody)(nil), // 6: milvus.proto.messages.CreateSegmentMessageBody + (*BeginTxnMessageBody)(nil), // 7: milvus.proto.messages.BeginTxnMessageBody + (*CommitTxnMessageBody)(nil), // 8: milvus.proto.messages.CommitTxnMessageBody + (*RollbackTxnMessageBody)(nil), // 9: milvus.proto.messages.RollbackTxnMessageBody + (*TxnMessageBody)(nil), // 10: milvus.proto.messages.TxnMessageBody + (*TimeTickMessageHeader)(nil), // 11: milvus.proto.messages.TimeTickMessageHeader + (*InsertMessageHeader)(nil), // 12: milvus.proto.messages.InsertMessageHeader + (*PartitionSegmentAssignment)(nil), // 13: milvus.proto.messages.PartitionSegmentAssignment + (*SegmentAssignment)(nil), // 14: milvus.proto.messages.SegmentAssignment + (*DeleteMessageHeader)(nil), // 15: milvus.proto.messages.DeleteMessageHeader + (*FlushMessageHeader)(nil), // 16: milvus.proto.messages.FlushMessageHeader + (*CreateSegmentMessageHeader)(nil), // 17: milvus.proto.messages.CreateSegmentMessageHeader + (*ManualFlushMessageHeader)(nil), // 18: milvus.proto.messages.ManualFlushMessageHeader + (*CreateCollectionMessageHeader)(nil), // 19: milvus.proto.messages.CreateCollectionMessageHeader + (*DropCollectionMessageHeader)(nil), // 20: milvus.proto.messages.DropCollectionMessageHeader + (*CreatePartitionMessageHeader)(nil), // 21: milvus.proto.messages.CreatePartitionMessageHeader + (*DropPartitionMessageHeader)(nil), // 22: milvus.proto.messages.DropPartitionMessageHeader + (*PutReplicateConfigMessageHeader)(nil), // 23: milvus.proto.messages.PutReplicateConfigMessageHeader + (*PutReplicateConfigMessageBody)(nil), // 24: milvus.proto.messages.PutReplicateConfigMessageBody + (*BeginTxnMessageHeader)(nil), // 25: milvus.proto.messages.BeginTxnMessageHeader + (*CommitTxnMessageHeader)(nil), // 26: milvus.proto.messages.CommitTxnMessageHeader + (*RollbackTxnMessageHeader)(nil), // 27: milvus.proto.messages.RollbackTxnMessageHeader + (*TxnMessageHeader)(nil), // 28: milvus.proto.messages.TxnMessageHeader + (*ImportMessageHeader)(nil), // 29: milvus.proto.messages.ImportMessageHeader + (*SchemaChangeMessageHeader)(nil), // 30: milvus.proto.messages.SchemaChangeMessageHeader + (*SchemaChangeMessageBody)(nil), // 31: milvus.proto.messages.SchemaChangeMessageBody + (*ManualFlushExtraResponse)(nil), // 32: milvus.proto.messages.ManualFlushExtraResponse + (*TxnContext)(nil), // 33: milvus.proto.messages.TxnContext + (*RMQMessageLayout)(nil), // 34: milvus.proto.messages.RMQMessageLayout + (*BroadcastHeader)(nil), // 35: milvus.proto.messages.BroadcastHeader + (*ReplicateHeader)(nil), // 36: milvus.proto.messages.ReplicateHeader + (*ResourceKey)(nil), // 37: milvus.proto.messages.ResourceKey + (*CipherHeader)(nil), // 38: milvus.proto.messages.CipherHeader + nil, // 39: milvus.proto.messages.Message.PropertiesEntry + nil, // 40: milvus.proto.messages.RMQMessageLayout.PropertiesEntry + (datapb.SegmentLevel)(0), // 41: milvus.proto.data.SegmentLevel + (*commonpb.ReplicateConfiguration)(nil), // 42: milvus.proto.common.ReplicateConfiguration + (*schemapb.CollectionSchema)(nil), // 43: milvus.proto.schema.CollectionSchema + (*commonpb.MessageID)(nil), // 44: milvus.proto.common.MessageID } var file_messages_proto_depIdxs = []int32{ - 38, // 0: milvus.proto.messages.Message.properties:type_name -> milvus.proto.messages.Message.PropertiesEntry - 3, // 1: milvus.proto.messages.ImmutableMessage.id:type_name -> milvus.proto.messages.MessageID - 39, // 2: milvus.proto.messages.ImmutableMessage.properties:type_name -> milvus.proto.messages.ImmutableMessage.PropertiesEntry - 4, // 3: milvus.proto.messages.TxnMessageBody.messages:type_name -> milvus.proto.messages.Message - 15, // 4: milvus.proto.messages.InsertMessageHeader.partitions:type_name -> milvus.proto.messages.PartitionSegmentAssignment - 16, // 5: milvus.proto.messages.PartitionSegmentAssignment.segment_assignment:type_name -> milvus.proto.messages.SegmentAssignment - 41, // 6: milvus.proto.messages.CreateSegmentMessageHeader.level:type_name -> milvus.proto.data.SegmentLevel - 42, // 7: milvus.proto.messages.SchemaChangeMessageBody.schema:type_name -> milvus.proto.schema.CollectionSchema - 40, // 8: milvus.proto.messages.RMQMessageLayout.properties:type_name -> milvus.proto.messages.RMQMessageLayout.PropertiesEntry - 36, // 9: milvus.proto.messages.BroadcastHeader.Resource_keys:type_name -> milvus.proto.messages.ResourceKey - 2, // 10: milvus.proto.messages.ResourceKey.domain:type_name -> milvus.proto.messages.ResourceDomain - 11, // [11:11] is the sub-list for method output_type - 11, // [11:11] is the sub-list for method input_type - 11, // [11:11] is the sub-list for extension type_name - 11, // [11:11] is the sub-list for extension extendee - 0, // [0:11] is the sub-list for field type_name + 39, // 0: milvus.proto.messages.Message.properties:type_name -> milvus.proto.messages.Message.PropertiesEntry + 3, // 1: milvus.proto.messages.TxnMessageBody.messages:type_name -> milvus.proto.messages.Message + 13, // 2: milvus.proto.messages.InsertMessageHeader.partitions:type_name -> milvus.proto.messages.PartitionSegmentAssignment + 14, // 3: milvus.proto.messages.PartitionSegmentAssignment.segment_assignment:type_name -> milvus.proto.messages.SegmentAssignment + 41, // 4: milvus.proto.messages.CreateSegmentMessageHeader.level:type_name -> milvus.proto.data.SegmentLevel + 42, // 5: milvus.proto.messages.PutReplicateConfigMessageHeader.replicate_configuration:type_name -> milvus.proto.common.ReplicateConfiguration + 43, // 6: milvus.proto.messages.SchemaChangeMessageBody.schema:type_name -> milvus.proto.schema.CollectionSchema + 40, // 7: milvus.proto.messages.RMQMessageLayout.properties:type_name -> milvus.proto.messages.RMQMessageLayout.PropertiesEntry + 37, // 8: milvus.proto.messages.BroadcastHeader.Resource_keys:type_name -> milvus.proto.messages.ResourceKey + 44, // 9: milvus.proto.messages.ReplicateHeader.message_id:type_name -> milvus.proto.common.MessageID + 44, // 10: milvus.proto.messages.ReplicateHeader.last_confirmed_message_id:type_name -> milvus.proto.common.MessageID + 2, // 11: milvus.proto.messages.ResourceKey.domain:type_name -> milvus.proto.messages.ResourceDomain + 12, // [12:12] is the sub-list for method output_type + 12, // [12:12] is the sub-list for method input_type + 12, // [12:12] is the sub-list for extension type_name + 12, // [12:12] is the sub-list for extension extendee + 0, // [0:12] is the sub-list for field type_name } func init() { file_messages_proto_init() } @@ -2420,18 +2500,6 @@ func file_messages_proto_init() { } if !protoimpl.UnsafeEnabled { file_messages_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MessageID); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Message); i { case 0: return &v.state @@ -2443,19 +2511,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ImmutableMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_messages_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*FlushMessageBody); i { case 0: return &v.state @@ -2467,7 +2523,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ManualFlushMessageBody); i { case 0: return &v.state @@ -2479,7 +2535,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CreateSegmentMessageBody); i { case 0: return &v.state @@ -2491,7 +2547,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*BeginTxnMessageBody); i { case 0: return &v.state @@ -2503,7 +2559,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CommitTxnMessageBody); i { case 0: return &v.state @@ -2515,7 +2571,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*RollbackTxnMessageBody); i { case 0: return &v.state @@ -2527,7 +2583,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*TxnMessageBody); i { case 0: return &v.state @@ -2539,7 +2595,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*TimeTickMessageHeader); i { case 0: return &v.state @@ -2551,7 +2607,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*InsertMessageHeader); i { case 0: return &v.state @@ -2563,7 +2619,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*PartitionSegmentAssignment); i { case 0: return &v.state @@ -2575,7 +2631,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*SegmentAssignment); i { case 0: return &v.state @@ -2587,7 +2643,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*DeleteMessageHeader); i { case 0: return &v.state @@ -2599,7 +2655,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*FlushMessageHeader); i { case 0: return &v.state @@ -2611,7 +2667,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CreateSegmentMessageHeader); i { case 0: return &v.state @@ -2623,7 +2679,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ManualFlushMessageHeader); i { case 0: return &v.state @@ -2635,7 +2691,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CreateCollectionMessageHeader); i { case 0: return &v.state @@ -2647,7 +2703,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*DropCollectionMessageHeader); i { case 0: return &v.state @@ -2659,7 +2715,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CreatePartitionMessageHeader); i { case 0: return &v.state @@ -2671,7 +2727,7 @@ func file_messages_proto_init() { return nil } } - file_messages_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { + file_messages_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*DropPartitionMessageHeader); i { case 0: return &v.state @@ -2683,6 +2739,30 @@ func file_messages_proto_init() { return nil } } + file_messages_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PutReplicateConfigMessageHeader); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PutReplicateConfigMessageBody); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } file_messages_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*BeginTxnMessageHeader); i { case 0: @@ -2816,7 +2896,7 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ResourceKey); i { + switch v := v.(*ReplicateHeader); i { case 0: return &v.state case 1: @@ -2828,6 +2908,18 @@ func file_messages_proto_init() { } } file_messages_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ResourceKey); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CipherHeader); i { case 0: return &v.state diff --git a/pkg/proto/streaming.proto b/pkg/proto/streaming.proto index 663f12ee59..46f20784a8 100644 --- a/pkg/proto/streaming.proto +++ b/pkg/proto/streaming.proto @@ -6,6 +6,7 @@ option go_package = "github.com/milvus-io/milvus/pkg/v2/proto/streamingpb"; import "data_coord.proto"; import "messages.proto"; +import "common.proto"; import "milvus.proto"; import "schema.proto"; import "google/protobuf/empty.proto"; @@ -99,6 +100,20 @@ message BroadcastTask { bytes acked_vchannel_bitmap = 3; // given vchannels that have been acked, the size of bitmap is same with message.BroadcastHeader().VChannels. } +// AckedResult is the result of the ack. +// It's a helper proto to help managing the consuming of broadcast message at coordinator. +message AckedResult { + repeated string channels = 1; // may be pchannel name or vchannel name. + repeated AckedCheckpoint acked_checkpoints = 2; // always same length with channels, not nil if acked. +} + +// AckedCheckpoint is the checkpoint that has been acked. +message AckedCheckpoint { + common.MessageID message_id = 1; // the message id that has been acked. + common.MessageID last_confirmed_message_id = 2; // the last confirmed message id that has been acked. + uint64 time_tick = 3; // the time tick of the message that has been acked. +} + // // Milvus Service // @@ -136,7 +151,7 @@ message BroadcastResponse { message BroadcastAckRequest { uint64 broadcast_id = 1 [deprecated = true]; // broadcast id. string vchannel = 2 [deprecated = true]; // the vchannel that acked the message. - messages.ImmutableMessage message = 3; // the message that to be acked. + common.ImmutableMessage message = 3; // the message that to be acked. } message BroadcastAckResponse { @@ -150,6 +165,19 @@ message BroadcastAckResponse { // Server: log coord. Running on every log node. // Client: all log publish/consuming node. service StreamingCoordAssignmentService { + // UpdateReplicateConfiguration applies a full replacement of the current + // replication configuration across Milvus clusters. + // + // Semantics: + // - The provided ReplicateConfiguration completely replaces any existing + // configuration persisted in the metadata store. + // - Passing an empty ReplicateConfiguration is treated as a "clear" + // operation, effectively removing all replication configuration. + // - The RPC is expected to be idempotent: submitting the same configuration + // multiple times must not cause side effects. + rpc UpdateReplicateConfiguration(UpdateReplicateConfigurationRequest) + returns (UpdateReplicateConfigurationResponse) {} + // UpdateWALBalancePolicy is used to update the WAL balance policy. // The policy is used to control the balance of the WAL. rpc UpdateWALBalancePolicy(UpdateWALBalancePolicyRequest) returns (UpdateWALBalancePolicyResponse) {}; @@ -161,6 +189,13 @@ service StreamingCoordAssignmentService { returns (stream AssignmentDiscoverResponse) {} } +message UpdateReplicateConfigurationRequest { + common.ReplicateConfiguration configuration = 1; +} + +// UpdateReplicateConfigurationResponse is the response of UpdateReplicateConfiguration service +message UpdateReplicateConfigurationResponse {} + // UpdateWALBalancePolicyRequest is the request to update the WAL balance policy. message UpdateWALBalancePolicyRequest { WALBalancePolicyConfig config = 1; @@ -214,9 +249,10 @@ message AssignmentDiscoverResponse { // FullStreamingNodeAssignmentWithVersion is the full assignment info of a log // node with version. message FullStreamingNodeAssignmentWithVersion { - VersionPair version = 1; - repeated StreamingNodeAssignment assignments = 2; - CChannelAssignment cchannel = 3; // Where the control channel located. + VersionPair version = 1; + repeated StreamingNodeAssignment assignments = 2; + CChannelAssignment cchannel = 3; // Where the control channel located. + common.ReplicateConfiguration replicate_configuration = 4; } // CChannelAssignment is the assignment info of a control channel. @@ -243,9 +279,9 @@ message DeliverPolicy { oneof policy { google.protobuf.Empty all = 1; // deliver all messages. google.protobuf.Empty latest = 2; // deliver the latest message. - messages.MessageID start_from = + common.MessageID start_from = 3; // deliver message from this message id. [startFrom, ...] - messages.MessageID start_after = + common.MessageID start_after = 4; // deliver message after this message id. (startAfter, ...] } } @@ -291,8 +327,9 @@ enum StreamingCode { STREAMING_CODE_INVAILD_ARGUMENT = 8; // invalid argument STREAMING_CODE_TRANSACTION_EXPIRED = 9; // transaction expired STREAMING_CODE_INVALID_TRANSACTION_STATE = 10; // invalid transaction state - STREAMING_CODE_UNRECOVERABLE = 11; // unrecoverable error + STREAMING_CODE_UNRECOVERABLE = 11; // unrecoverable error STREAMING_CODE_RESOURCE_ACQUIRED = 12; // resource is acquired by other operation + STREAMING_CODE_REPLICATE_VIOLATION = 13; // replicate violation STREAMING_CODE_UNKNOWN = 999; // unknown error } @@ -311,6 +348,10 @@ message StreamingError { // write on that log node. Server: all log node. Running on every log node. // Client: all log produce or consuming node. service StreamingNodeHandlerService { + // GetReplicateCheckpoint returns the WAL checkpoint that will be used to create scanner + // from the correct position, ensuring no duplicate or missing messages. + rpc GetReplicateCheckpoint(GetReplicateCheckpointRequest) returns (GetReplicateCheckpointResponse) {} + // Produce is a bi-directional streaming RPC to send messages to a channel. // All messages sent to a channel will be assigned a unique messageID. // The messageID is used to identify the message in the channel. @@ -329,6 +370,16 @@ service StreamingNodeHandlerService { rpc Consume(stream ConsumeRequest) returns (stream ConsumeResponse) {}; } +// GetReplicateCheckpointRequest is the request of GetReplicateCheckpoint service. +message GetReplicateCheckpointRequest { + PChannelInfo pchannel = 1; +} + +// GetReplicateCheckpointResponse is the response of GetReplicateCheckpoint service. +message GetReplicateCheckpointResponse { + common.ReplicateCheckpoint checkpoint = 1; +} + // ProduceRequest is the request of the Produce RPC. // Channel name will be passthrough in the header of stream bu not in the // request body. @@ -366,7 +417,7 @@ message ProduceResponse { // CreateProducerResponse is the result of the CreateProducer RPC. message CreateProducerResponse { - string wal_name = 1; // wal name at server side. + string wal_name = 1 [deprecated = true]; // wal name at server side. int64 producer_server_id = 2; // A unique producer server id on streamingnode // for this producer in streamingnode lifetime. // Is used to identify the producer in streamingnode for other unary grpc @@ -385,7 +436,7 @@ message ProduceMessageResponse { // ProduceMessageResponseResult is the result of the produce message streaming // RPC. message ProduceMessageResponseResult { - messages.MessageID id = 1; // the offset of the message in the channel. + common.MessageID id = 1; // the offset of the message in the channel. uint64 timetick = 2; // the timetick of that message sent. messages.TxnContext txnContext = 3; // the txn context of the message. google.protobuf.Any extra = 4; // the extra message. @@ -466,7 +517,7 @@ message ConsumeResponse { } message CreateConsumerResponse { - string wal_name = 1; // wal name at server side. + string wal_name = 1 [deprecated = true]; // wal name at server side. // A unique consumer id on streamingnode for this // consumer in streamingnode lifetime. int64 consumer_server_id = 2; @@ -474,7 +525,7 @@ message CreateConsumerResponse { message ConsumeMessageReponse { int64 consumer_id = 1; - messages.ImmutableMessage message = 2; + common.ImmutableMessage message = 2; } message CloseConsumerResponse {} @@ -638,7 +689,7 @@ message SegmentAssignmentStat { // The WALCheckpoint that is used to recovery the wal scanner. message WALCheckpoint { - messages.MessageID message_id = 1; // From here to recover all uncommited info. + common.MessageID message_id = 1; // From here to recover all uncommited info. // e.g., primary key index, segment assignment info, vchannel info... // because current data path flush is slow, and managed by the coordinator, current current is not apply to it. // @@ -646,4 +697,21 @@ message WALCheckpoint { uint64 time_tick = 2; // The timetick of checkpoint, keep consistecy with message_id. // It's a hint for easier debugging. int64 recovery_magic = 3; // The recovery version of the checkpoint, it's used to hint the future recovery info upgrading. -} \ No newline at end of file + // The wal name of the checkpoint. + common.ReplicateConfiguration replicate_config = 4; // if the wal join a replicated clusters, the replicate config is not null, + common.ReplicateCheckpoint replicate_checkpoint = 5; // if the wal is replicated from remote cluster, the checkpoint is not null, + // It's used to recover the replication state for remote cluster. +} + +// ReplicateConfigurationMeta is the replicate configuration of the wal. +message ReplicateConfigurationMeta { + common.ReplicateConfiguration replicate_configuration = 1; + AckedResult acked_result = 2; // a acked helper to help managing the consuming of PutReplicateConfigMessageV2 message at coordinator. +} + +message ReplicatePChannelMeta { + string source_channel_name = 1; + string target_channel_name = 2; + common.MilvusCluster target_cluster = 3; + common.ReplicateCheckpoint initialized_checkpoint = 4; +} diff --git a/pkg/proto/streamingpb/streaming.pb.go b/pkg/proto/streamingpb/streaming.pb.go index eaa1f6d9ef..f26c3bd548 100644 --- a/pkg/proto/streamingpb/streaming.pb.go +++ b/pkg/proto/streamingpb/streaming.pb.go @@ -7,6 +7,7 @@ package streamingpb import ( + commonpb "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" milvuspb "github.com/milvus-io/milvus-proto/go-api/v2/milvuspb" schemapb "github.com/milvus-io/milvus-proto/go-api/v2/schemapb" datapb "github.com/milvus-io/milvus/pkg/v2/proto/datapb" @@ -200,6 +201,7 @@ const ( StreamingCode_STREAMING_CODE_INVALID_TRANSACTION_STATE StreamingCode = 10 // invalid transaction state StreamingCode_STREAMING_CODE_UNRECOVERABLE StreamingCode = 11 // unrecoverable error StreamingCode_STREAMING_CODE_RESOURCE_ACQUIRED StreamingCode = 12 // resource is acquired by other operation + StreamingCode_STREAMING_CODE_REPLICATE_VIOLATION StreamingCode = 13 // replicate violation StreamingCode_STREAMING_CODE_UNKNOWN StreamingCode = 999 // unknown error ) @@ -219,6 +221,7 @@ var ( 10: "STREAMING_CODE_INVALID_TRANSACTION_STATE", 11: "STREAMING_CODE_UNRECOVERABLE", 12: "STREAMING_CODE_RESOURCE_ACQUIRED", + 13: "STREAMING_CODE_REPLICATE_VIOLATION", 999: "STREAMING_CODE_UNKNOWN", } StreamingCode_value = map[string]int32{ @@ -235,6 +238,7 @@ var ( "STREAMING_CODE_INVALID_TRANSACTION_STATE": 10, "STREAMING_CODE_UNRECOVERABLE": 11, "STREAMING_CODE_RESOURCE_ACQUIRED": 12, + "STREAMING_CODE_REPLICATE_VIOLATION": 13, "STREAMING_CODE_UNKNOWN": 999, } ) @@ -845,6 +849,127 @@ func (x *BroadcastTask) GetAckedVchannelBitmap() []byte { return nil } +// AckedResult is the result of the ack. +// It's a helper proto to help managing the consuming of broadcast message at coordinator. +type AckedResult struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Channels []string `protobuf:"bytes,1,rep,name=channels,proto3" json:"channels,omitempty"` // may be pchannel name or vchannel name. + AckedCheckpoints []*AckedCheckpoint `protobuf:"bytes,2,rep,name=acked_checkpoints,json=ackedCheckpoints,proto3" json:"acked_checkpoints,omitempty"` // always same length with channels, not nil if acked. +} + +func (x *AckedResult) Reset() { + *x = AckedResult{} + if protoimpl.UnsafeEnabled { + mi := &file_streaming_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AckedResult) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AckedResult) ProtoMessage() {} + +func (x *AckedResult) ProtoReflect() protoreflect.Message { + mi := &file_streaming_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AckedResult.ProtoReflect.Descriptor instead. +func (*AckedResult) Descriptor() ([]byte, []int) { + return file_streaming_proto_rawDescGZIP(), []int{7} +} + +func (x *AckedResult) GetChannels() []string { + if x != nil { + return x.Channels + } + return nil +} + +func (x *AckedResult) GetAckedCheckpoints() []*AckedCheckpoint { + if x != nil { + return x.AckedCheckpoints + } + return nil +} + +// AckedCheckpoint is the checkpoint that has been acked. +type AckedCheckpoint struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + MessageId *commonpb.MessageID `protobuf:"bytes,1,opt,name=message_id,json=messageId,proto3" json:"message_id,omitempty"` // the message id that has been acked. + LastConfirmedMessageId *commonpb.MessageID `protobuf:"bytes,2,opt,name=last_confirmed_message_id,json=lastConfirmedMessageId,proto3" json:"last_confirmed_message_id,omitempty"` // the last confirmed message id that has been acked. + TimeTick uint64 `protobuf:"varint,3,opt,name=time_tick,json=timeTick,proto3" json:"time_tick,omitempty"` // the time tick of the message that has been acked. +} + +func (x *AckedCheckpoint) Reset() { + *x = AckedCheckpoint{} + if protoimpl.UnsafeEnabled { + mi := &file_streaming_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AckedCheckpoint) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AckedCheckpoint) ProtoMessage() {} + +func (x *AckedCheckpoint) ProtoReflect() protoreflect.Message { + mi := &file_streaming_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AckedCheckpoint.ProtoReflect.Descriptor instead. +func (*AckedCheckpoint) Descriptor() ([]byte, []int) { + return file_streaming_proto_rawDescGZIP(), []int{8} +} + +func (x *AckedCheckpoint) GetMessageId() *commonpb.MessageID { + if x != nil { + return x.MessageId + } + return nil +} + +func (x *AckedCheckpoint) GetLastConfirmedMessageId() *commonpb.MessageID { + if x != nil { + return x.LastConfirmedMessageId + } + return nil +} + +func (x *AckedCheckpoint) GetTimeTick() uint64 { + if x != nil { + return x.TimeTick + } + return 0 +} + // BroadcastRequest is the request of the Broadcast RPC. type BroadcastRequest struct { state protoimpl.MessageState @@ -857,7 +982,7 @@ type BroadcastRequest struct { func (x *BroadcastRequest) Reset() { *x = BroadcastRequest{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[7] + mi := &file_streaming_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -870,7 +995,7 @@ func (x *BroadcastRequest) String() string { func (*BroadcastRequest) ProtoMessage() {} func (x *BroadcastRequest) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[7] + mi := &file_streaming_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -883,7 +1008,7 @@ func (x *BroadcastRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use BroadcastRequest.ProtoReflect.Descriptor instead. func (*BroadcastRequest) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{7} + return file_streaming_proto_rawDescGZIP(), []int{9} } func (x *BroadcastRequest) GetMessage() *messagespb.Message { @@ -906,7 +1031,7 @@ type BroadcastResponse struct { func (x *BroadcastResponse) Reset() { *x = BroadcastResponse{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[8] + mi := &file_streaming_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -919,7 +1044,7 @@ func (x *BroadcastResponse) String() string { func (*BroadcastResponse) ProtoMessage() {} func (x *BroadcastResponse) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[8] + mi := &file_streaming_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -932,7 +1057,7 @@ func (x *BroadcastResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use BroadcastResponse.ProtoReflect.Descriptor instead. func (*BroadcastResponse) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{8} + return file_streaming_proto_rawDescGZIP(), []int{10} } func (x *BroadcastResponse) GetResults() map[string]*ProduceMessageResponseResult { @@ -957,14 +1082,14 @@ type BroadcastAckRequest struct { // Deprecated: Marked as deprecated in streaming.proto. BroadcastId uint64 `protobuf:"varint,1,opt,name=broadcast_id,json=broadcastId,proto3" json:"broadcast_id,omitempty"` // broadcast id. // Deprecated: Marked as deprecated in streaming.proto. - Vchannel string `protobuf:"bytes,2,opt,name=vchannel,proto3" json:"vchannel,omitempty"` // the vchannel that acked the message. - Message *messagespb.ImmutableMessage `protobuf:"bytes,3,opt,name=message,proto3" json:"message,omitempty"` // the message that to be acked. + Vchannel string `protobuf:"bytes,2,opt,name=vchannel,proto3" json:"vchannel,omitempty"` // the vchannel that acked the message. + Message *commonpb.ImmutableMessage `protobuf:"bytes,3,opt,name=message,proto3" json:"message,omitempty"` // the message that to be acked. } func (x *BroadcastAckRequest) Reset() { *x = BroadcastAckRequest{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[9] + mi := &file_streaming_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -977,7 +1102,7 @@ func (x *BroadcastAckRequest) String() string { func (*BroadcastAckRequest) ProtoMessage() {} func (x *BroadcastAckRequest) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[9] + mi := &file_streaming_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -990,7 +1115,7 @@ func (x *BroadcastAckRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use BroadcastAckRequest.ProtoReflect.Descriptor instead. func (*BroadcastAckRequest) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{9} + return file_streaming_proto_rawDescGZIP(), []int{11} } // Deprecated: Marked as deprecated in streaming.proto. @@ -1009,7 +1134,7 @@ func (x *BroadcastAckRequest) GetVchannel() string { return "" } -func (x *BroadcastAckRequest) GetMessage() *messagespb.ImmutableMessage { +func (x *BroadcastAckRequest) GetMessage() *commonpb.ImmutableMessage { if x != nil { return x.Message } @@ -1025,7 +1150,7 @@ type BroadcastAckResponse struct { func (x *BroadcastAckResponse) Reset() { *x = BroadcastAckResponse{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[10] + mi := &file_streaming_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1038,7 +1163,7 @@ func (x *BroadcastAckResponse) String() string { func (*BroadcastAckResponse) ProtoMessage() {} func (x *BroadcastAckResponse) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[10] + mi := &file_streaming_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1051,7 +1176,93 @@ func (x *BroadcastAckResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use BroadcastAckResponse.ProtoReflect.Descriptor instead. func (*BroadcastAckResponse) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{10} + return file_streaming_proto_rawDescGZIP(), []int{12} +} + +type UpdateReplicateConfigurationRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Configuration *commonpb.ReplicateConfiguration `protobuf:"bytes,1,opt,name=configuration,proto3" json:"configuration,omitempty"` +} + +func (x *UpdateReplicateConfigurationRequest) Reset() { + *x = UpdateReplicateConfigurationRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_streaming_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateReplicateConfigurationRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateReplicateConfigurationRequest) ProtoMessage() {} + +func (x *UpdateReplicateConfigurationRequest) ProtoReflect() protoreflect.Message { + mi := &file_streaming_proto_msgTypes[13] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateReplicateConfigurationRequest.ProtoReflect.Descriptor instead. +func (*UpdateReplicateConfigurationRequest) Descriptor() ([]byte, []int) { + return file_streaming_proto_rawDescGZIP(), []int{13} +} + +func (x *UpdateReplicateConfigurationRequest) GetConfiguration() *commonpb.ReplicateConfiguration { + if x != nil { + return x.Configuration + } + return nil +} + +// UpdateReplicateConfigurationResponse is the response of UpdateReplicateConfiguration service +type UpdateReplicateConfigurationResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *UpdateReplicateConfigurationResponse) Reset() { + *x = UpdateReplicateConfigurationResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_streaming_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateReplicateConfigurationResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateReplicateConfigurationResponse) ProtoMessage() {} + +func (x *UpdateReplicateConfigurationResponse) ProtoReflect() protoreflect.Message { + mi := &file_streaming_proto_msgTypes[14] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateReplicateConfigurationResponse.ProtoReflect.Descriptor instead. +func (*UpdateReplicateConfigurationResponse) Descriptor() ([]byte, []int) { + return file_streaming_proto_rawDescGZIP(), []int{14} } // UpdateWALBalancePolicyRequest is the request to update the WAL balance policy. @@ -1068,7 +1279,7 @@ type UpdateWALBalancePolicyRequest struct { func (x *UpdateWALBalancePolicyRequest) Reset() { *x = UpdateWALBalancePolicyRequest{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[11] + mi := &file_streaming_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1081,7 +1292,7 @@ func (x *UpdateWALBalancePolicyRequest) String() string { func (*UpdateWALBalancePolicyRequest) ProtoMessage() {} func (x *UpdateWALBalancePolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[11] + mi := &file_streaming_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1094,7 +1305,7 @@ func (x *UpdateWALBalancePolicyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateWALBalancePolicyRequest.ProtoReflect.Descriptor instead. func (*UpdateWALBalancePolicyRequest) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{11} + return file_streaming_proto_rawDescGZIP(), []int{15} } func (x *UpdateWALBalancePolicyRequest) GetConfig() *WALBalancePolicyConfig { @@ -1129,7 +1340,7 @@ type WALBalancePolicyConfig struct { func (x *WALBalancePolicyConfig) Reset() { *x = WALBalancePolicyConfig{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[12] + mi := &file_streaming_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1142,7 +1353,7 @@ func (x *WALBalancePolicyConfig) String() string { func (*WALBalancePolicyConfig) ProtoMessage() {} func (x *WALBalancePolicyConfig) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[12] + mi := &file_streaming_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1155,7 +1366,7 @@ func (x *WALBalancePolicyConfig) ProtoReflect() protoreflect.Message { // Deprecated: Use WALBalancePolicyConfig.ProtoReflect.Descriptor instead. func (*WALBalancePolicyConfig) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{12} + return file_streaming_proto_rawDescGZIP(), []int{16} } func (x *WALBalancePolicyConfig) GetAllowRebalance() bool { @@ -1177,7 +1388,7 @@ type WALBalancePolicyNodes struct { func (x *WALBalancePolicyNodes) Reset() { *x = WALBalancePolicyNodes{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[13] + mi := &file_streaming_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1190,7 +1401,7 @@ func (x *WALBalancePolicyNodes) String() string { func (*WALBalancePolicyNodes) ProtoMessage() {} func (x *WALBalancePolicyNodes) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[13] + mi := &file_streaming_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1203,7 +1414,7 @@ func (x *WALBalancePolicyNodes) ProtoReflect() protoreflect.Message { // Deprecated: Use WALBalancePolicyNodes.ProtoReflect.Descriptor instead. func (*WALBalancePolicyNodes) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{13} + return file_streaming_proto_rawDescGZIP(), []int{17} } func (x *WALBalancePolicyNodes) GetFreezeNodeIds() []int64 { @@ -1232,7 +1443,7 @@ type UpdateWALBalancePolicyResponse struct { func (x *UpdateWALBalancePolicyResponse) Reset() { *x = UpdateWALBalancePolicyResponse{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[14] + mi := &file_streaming_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1245,7 +1456,7 @@ func (x *UpdateWALBalancePolicyResponse) String() string { func (*UpdateWALBalancePolicyResponse) ProtoMessage() {} func (x *UpdateWALBalancePolicyResponse) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[14] + mi := &file_streaming_proto_msgTypes[18] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1258,7 +1469,7 @@ func (x *UpdateWALBalancePolicyResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateWALBalancePolicyResponse.ProtoReflect.Descriptor instead. func (*UpdateWALBalancePolicyResponse) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{14} + return file_streaming_proto_rawDescGZIP(), []int{18} } func (x *UpdateWALBalancePolicyResponse) GetConfig() *WALBalancePolicyConfig { @@ -1291,7 +1502,7 @@ type AssignmentDiscoverRequest struct { func (x *AssignmentDiscoverRequest) Reset() { *x = AssignmentDiscoverRequest{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[15] + mi := &file_streaming_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1304,7 +1515,7 @@ func (x *AssignmentDiscoverRequest) String() string { func (*AssignmentDiscoverRequest) ProtoMessage() {} func (x *AssignmentDiscoverRequest) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[15] + mi := &file_streaming_proto_msgTypes[19] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1317,7 +1528,7 @@ func (x *AssignmentDiscoverRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use AssignmentDiscoverRequest.ProtoReflect.Descriptor instead. func (*AssignmentDiscoverRequest) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{15} + return file_streaming_proto_rawDescGZIP(), []int{19} } func (m *AssignmentDiscoverRequest) GetCommand() isAssignmentDiscoverRequest_Command { @@ -1371,7 +1582,7 @@ type ReportAssignmentErrorRequest struct { func (x *ReportAssignmentErrorRequest) Reset() { *x = ReportAssignmentErrorRequest{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[16] + mi := &file_streaming_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1384,7 +1595,7 @@ func (x *ReportAssignmentErrorRequest) String() string { func (*ReportAssignmentErrorRequest) ProtoMessage() {} func (x *ReportAssignmentErrorRequest) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[16] + mi := &file_streaming_proto_msgTypes[20] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1397,7 +1608,7 @@ func (x *ReportAssignmentErrorRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ReportAssignmentErrorRequest.ProtoReflect.Descriptor instead. func (*ReportAssignmentErrorRequest) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{16} + return file_streaming_proto_rawDescGZIP(), []int{20} } func (x *ReportAssignmentErrorRequest) GetPchannel() *PChannelInfo { @@ -1424,7 +1635,7 @@ type CloseAssignmentDiscoverRequest struct { func (x *CloseAssignmentDiscoverRequest) Reset() { *x = CloseAssignmentDiscoverRequest{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[17] + mi := &file_streaming_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1437,7 +1648,7 @@ func (x *CloseAssignmentDiscoverRequest) String() string { func (*CloseAssignmentDiscoverRequest) ProtoMessage() {} func (x *CloseAssignmentDiscoverRequest) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[17] + mi := &file_streaming_proto_msgTypes[21] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1450,7 +1661,7 @@ func (x *CloseAssignmentDiscoverRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CloseAssignmentDiscoverRequest.ProtoReflect.Descriptor instead. func (*CloseAssignmentDiscoverRequest) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{17} + return file_streaming_proto_rawDescGZIP(), []int{21} } // AssignmentDiscoverResponse is the response of Discovery @@ -1469,7 +1680,7 @@ type AssignmentDiscoverResponse struct { func (x *AssignmentDiscoverResponse) Reset() { *x = AssignmentDiscoverResponse{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[18] + mi := &file_streaming_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1482,7 +1693,7 @@ func (x *AssignmentDiscoverResponse) String() string { func (*AssignmentDiscoverResponse) ProtoMessage() {} func (x *AssignmentDiscoverResponse) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[18] + mi := &file_streaming_proto_msgTypes[22] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1495,7 +1706,7 @@ func (x *AssignmentDiscoverResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use AssignmentDiscoverResponse.ProtoReflect.Descriptor instead. func (*AssignmentDiscoverResponse) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{18} + return file_streaming_proto_rawDescGZIP(), []int{22} } func (m *AssignmentDiscoverResponse) GetResponse() isAssignmentDiscoverResponse_Response { @@ -1543,15 +1754,16 @@ type FullStreamingNodeAssignmentWithVersion struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Version *VersionPair `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"` - Assignments []*StreamingNodeAssignment `protobuf:"bytes,2,rep,name=assignments,proto3" json:"assignments,omitempty"` - Cchannel *CChannelAssignment `protobuf:"bytes,3,opt,name=cchannel,proto3" json:"cchannel,omitempty"` // Where the control channel located. + Version *VersionPair `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"` + Assignments []*StreamingNodeAssignment `protobuf:"bytes,2,rep,name=assignments,proto3" json:"assignments,omitempty"` + Cchannel *CChannelAssignment `protobuf:"bytes,3,opt,name=cchannel,proto3" json:"cchannel,omitempty"` // Where the control channel located. + ReplicateConfiguration *commonpb.ReplicateConfiguration `protobuf:"bytes,4,opt,name=replicate_configuration,json=replicateConfiguration,proto3" json:"replicate_configuration,omitempty"` } func (x *FullStreamingNodeAssignmentWithVersion) Reset() { *x = FullStreamingNodeAssignmentWithVersion{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[19] + mi := &file_streaming_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1564,7 +1776,7 @@ func (x *FullStreamingNodeAssignmentWithVersion) String() string { func (*FullStreamingNodeAssignmentWithVersion) ProtoMessage() {} func (x *FullStreamingNodeAssignmentWithVersion) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[19] + mi := &file_streaming_proto_msgTypes[23] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1577,7 +1789,7 @@ func (x *FullStreamingNodeAssignmentWithVersion) ProtoReflect() protoreflect.Mes // Deprecated: Use FullStreamingNodeAssignmentWithVersion.ProtoReflect.Descriptor instead. func (*FullStreamingNodeAssignmentWithVersion) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{19} + return file_streaming_proto_rawDescGZIP(), []int{23} } func (x *FullStreamingNodeAssignmentWithVersion) GetVersion() *VersionPair { @@ -1601,6 +1813,13 @@ func (x *FullStreamingNodeAssignmentWithVersion) GetCchannel() *CChannelAssignme return nil } +func (x *FullStreamingNodeAssignmentWithVersion) GetReplicateConfiguration() *commonpb.ReplicateConfiguration { + if x != nil { + return x.ReplicateConfiguration + } + return nil +} + // CChannelAssignment is the assignment info of a control channel. type CChannelAssignment struct { state protoimpl.MessageState @@ -1613,7 +1832,7 @@ type CChannelAssignment struct { func (x *CChannelAssignment) Reset() { *x = CChannelAssignment{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[20] + mi := &file_streaming_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1626,7 +1845,7 @@ func (x *CChannelAssignment) String() string { func (*CChannelAssignment) ProtoMessage() {} func (x *CChannelAssignment) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[20] + mi := &file_streaming_proto_msgTypes[24] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1639,7 +1858,7 @@ func (x *CChannelAssignment) ProtoReflect() protoreflect.Message { // Deprecated: Use CChannelAssignment.ProtoReflect.Descriptor instead. func (*CChannelAssignment) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{20} + return file_streaming_proto_rawDescGZIP(), []int{24} } func (x *CChannelAssignment) GetMeta() *CChannelMeta { @@ -1658,7 +1877,7 @@ type CloseAssignmentDiscoverResponse struct { func (x *CloseAssignmentDiscoverResponse) Reset() { *x = CloseAssignmentDiscoverResponse{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[21] + mi := &file_streaming_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1671,7 +1890,7 @@ func (x *CloseAssignmentDiscoverResponse) String() string { func (*CloseAssignmentDiscoverResponse) ProtoMessage() {} func (x *CloseAssignmentDiscoverResponse) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[21] + mi := &file_streaming_proto_msgTypes[25] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1684,7 +1903,7 @@ func (x *CloseAssignmentDiscoverResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CloseAssignmentDiscoverResponse.ProtoReflect.Descriptor instead. func (*CloseAssignmentDiscoverResponse) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{21} + return file_streaming_proto_rawDescGZIP(), []int{25} } // StreamingNodeInfo is the information of a streaming node. @@ -1700,7 +1919,7 @@ type StreamingNodeInfo struct { func (x *StreamingNodeInfo) Reset() { *x = StreamingNodeInfo{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[22] + mi := &file_streaming_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1713,7 +1932,7 @@ func (x *StreamingNodeInfo) String() string { func (*StreamingNodeInfo) ProtoMessage() {} func (x *StreamingNodeInfo) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[22] + mi := &file_streaming_proto_msgTypes[26] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1726,7 +1945,7 @@ func (x *StreamingNodeInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use StreamingNodeInfo.ProtoReflect.Descriptor instead. func (*StreamingNodeInfo) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{22} + return file_streaming_proto_rawDescGZIP(), []int{26} } func (x *StreamingNodeInfo) GetServerId() int64 { @@ -1756,7 +1975,7 @@ type StreamingNodeAssignment struct { func (x *StreamingNodeAssignment) Reset() { *x = StreamingNodeAssignment{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[23] + mi := &file_streaming_proto_msgTypes[27] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1769,7 +1988,7 @@ func (x *StreamingNodeAssignment) String() string { func (*StreamingNodeAssignment) ProtoMessage() {} func (x *StreamingNodeAssignment) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[23] + mi := &file_streaming_proto_msgTypes[27] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1782,7 +2001,7 @@ func (x *StreamingNodeAssignment) ProtoReflect() protoreflect.Message { // Deprecated: Use StreamingNodeAssignment.ProtoReflect.Descriptor instead. func (*StreamingNodeAssignment) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{23} + return file_streaming_proto_rawDescGZIP(), []int{27} } func (x *StreamingNodeAssignment) GetNode() *StreamingNodeInfo { @@ -1817,7 +2036,7 @@ type DeliverPolicy struct { func (x *DeliverPolicy) Reset() { *x = DeliverPolicy{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[24] + mi := &file_streaming_proto_msgTypes[28] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1830,7 +2049,7 @@ func (x *DeliverPolicy) String() string { func (*DeliverPolicy) ProtoMessage() {} func (x *DeliverPolicy) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[24] + mi := &file_streaming_proto_msgTypes[28] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1843,7 +2062,7 @@ func (x *DeliverPolicy) ProtoReflect() protoreflect.Message { // Deprecated: Use DeliverPolicy.ProtoReflect.Descriptor instead. func (*DeliverPolicy) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{24} + return file_streaming_proto_rawDescGZIP(), []int{28} } func (m *DeliverPolicy) GetPolicy() isDeliverPolicy_Policy { @@ -1867,14 +2086,14 @@ func (x *DeliverPolicy) GetLatest() *emptypb.Empty { return nil } -func (x *DeliverPolicy) GetStartFrom() *messagespb.MessageID { +func (x *DeliverPolicy) GetStartFrom() *commonpb.MessageID { if x, ok := x.GetPolicy().(*DeliverPolicy_StartFrom); ok { return x.StartFrom } return nil } -func (x *DeliverPolicy) GetStartAfter() *messagespb.MessageID { +func (x *DeliverPolicy) GetStartAfter() *commonpb.MessageID { if x, ok := x.GetPolicy().(*DeliverPolicy_StartAfter); ok { return x.StartAfter } @@ -1894,11 +2113,11 @@ type DeliverPolicy_Latest struct { } type DeliverPolicy_StartFrom struct { - StartFrom *messagespb.MessageID `protobuf:"bytes,3,opt,name=start_from,json=startFrom,proto3,oneof"` // deliver message from this message id. [startFrom, ...] + StartFrom *commonpb.MessageID `protobuf:"bytes,3,opt,name=start_from,json=startFrom,proto3,oneof"` // deliver message from this message id. [startFrom, ...] } type DeliverPolicy_StartAfter struct { - StartAfter *messagespb.MessageID `protobuf:"bytes,4,opt,name=start_after,json=startAfter,proto3,oneof"` // deliver message after this message id. (startAfter, ...] + StartAfter *commonpb.MessageID `protobuf:"bytes,4,opt,name=start_after,json=startAfter,proto3,oneof"` // deliver message after this message id. (startAfter, ...] } func (*DeliverPolicy_All) isDeliverPolicy_Policy() {} @@ -1926,7 +2145,7 @@ type DeliverFilter struct { func (x *DeliverFilter) Reset() { *x = DeliverFilter{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[25] + mi := &file_streaming_proto_msgTypes[29] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1939,7 +2158,7 @@ func (x *DeliverFilter) String() string { func (*DeliverFilter) ProtoMessage() {} func (x *DeliverFilter) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[25] + mi := &file_streaming_proto_msgTypes[29] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1952,7 +2171,7 @@ func (x *DeliverFilter) ProtoReflect() protoreflect.Message { // Deprecated: Use DeliverFilter.ProtoReflect.Descriptor instead. func (*DeliverFilter) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{25} + return file_streaming_proto_rawDescGZIP(), []int{29} } func (m *DeliverFilter) GetFilter() isDeliverFilter_Filter { @@ -2018,7 +2237,7 @@ type DeliverFilterTimeTickGT struct { func (x *DeliverFilterTimeTickGT) Reset() { *x = DeliverFilterTimeTickGT{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[26] + mi := &file_streaming_proto_msgTypes[30] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2031,7 +2250,7 @@ func (x *DeliverFilterTimeTickGT) String() string { func (*DeliverFilterTimeTickGT) ProtoMessage() {} func (x *DeliverFilterTimeTickGT) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[26] + mi := &file_streaming_proto_msgTypes[30] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2044,7 +2263,7 @@ func (x *DeliverFilterTimeTickGT) ProtoReflect() protoreflect.Message { // Deprecated: Use DeliverFilterTimeTickGT.ProtoReflect.Descriptor instead. func (*DeliverFilterTimeTickGT) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{26} + return file_streaming_proto_rawDescGZIP(), []int{30} } func (x *DeliverFilterTimeTickGT) GetTimeTick() uint64 { @@ -2067,7 +2286,7 @@ type DeliverFilterTimeTickGTE struct { func (x *DeliverFilterTimeTickGTE) Reset() { *x = DeliverFilterTimeTickGTE{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[27] + mi := &file_streaming_proto_msgTypes[31] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2080,7 +2299,7 @@ func (x *DeliverFilterTimeTickGTE) String() string { func (*DeliverFilterTimeTickGTE) ProtoMessage() {} func (x *DeliverFilterTimeTickGTE) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[27] + mi := &file_streaming_proto_msgTypes[31] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2093,7 +2312,7 @@ func (x *DeliverFilterTimeTickGTE) ProtoReflect() protoreflect.Message { // Deprecated: Use DeliverFilterTimeTickGTE.ProtoReflect.Descriptor instead. func (*DeliverFilterTimeTickGTE) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{27} + return file_streaming_proto_rawDescGZIP(), []int{31} } func (x *DeliverFilterTimeTickGTE) GetTimeTick() uint64 { @@ -2115,7 +2334,7 @@ type DeliverFilterMessageType struct { func (x *DeliverFilterMessageType) Reset() { *x = DeliverFilterMessageType{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[28] + mi := &file_streaming_proto_msgTypes[32] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2128,7 +2347,7 @@ func (x *DeliverFilterMessageType) String() string { func (*DeliverFilterMessageType) ProtoMessage() {} func (x *DeliverFilterMessageType) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[28] + mi := &file_streaming_proto_msgTypes[32] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2141,7 +2360,7 @@ func (x *DeliverFilterMessageType) ProtoReflect() protoreflect.Message { // Deprecated: Use DeliverFilterMessageType.ProtoReflect.Descriptor instead. func (*DeliverFilterMessageType) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{28} + return file_streaming_proto_rawDescGZIP(), []int{32} } func (x *DeliverFilterMessageType) GetMessageTypes() []messagespb.MessageType { @@ -2164,7 +2383,7 @@ type StreamingError struct { func (x *StreamingError) Reset() { *x = StreamingError{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[29] + mi := &file_streaming_proto_msgTypes[33] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2177,7 +2396,7 @@ func (x *StreamingError) String() string { func (*StreamingError) ProtoMessage() {} func (x *StreamingError) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[29] + mi := &file_streaming_proto_msgTypes[33] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2190,7 +2409,7 @@ func (x *StreamingError) ProtoReflect() protoreflect.Message { // Deprecated: Use StreamingError.ProtoReflect.Descriptor instead. func (*StreamingError) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{29} + return file_streaming_proto_rawDescGZIP(), []int{33} } func (x *StreamingError) GetCode() StreamingCode { @@ -2207,6 +2426,102 @@ func (x *StreamingError) GetCause() string { return "" } +// GetReplicateCheckpointRequest is the request of GetReplicateCheckpoint service. +type GetReplicateCheckpointRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Pchannel *PChannelInfo `protobuf:"bytes,1,opt,name=pchannel,proto3" json:"pchannel,omitempty"` +} + +func (x *GetReplicateCheckpointRequest) Reset() { + *x = GetReplicateCheckpointRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_streaming_proto_msgTypes[34] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetReplicateCheckpointRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetReplicateCheckpointRequest) ProtoMessage() {} + +func (x *GetReplicateCheckpointRequest) ProtoReflect() protoreflect.Message { + mi := &file_streaming_proto_msgTypes[34] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetReplicateCheckpointRequest.ProtoReflect.Descriptor instead. +func (*GetReplicateCheckpointRequest) Descriptor() ([]byte, []int) { + return file_streaming_proto_rawDescGZIP(), []int{34} +} + +func (x *GetReplicateCheckpointRequest) GetPchannel() *PChannelInfo { + if x != nil { + return x.Pchannel + } + return nil +} + +// GetReplicateCheckpointResponse is the response of GetReplicateCheckpoint service. +type GetReplicateCheckpointResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Checkpoint *commonpb.ReplicateCheckpoint `protobuf:"bytes,1,opt,name=checkpoint,proto3" json:"checkpoint,omitempty"` +} + +func (x *GetReplicateCheckpointResponse) Reset() { + *x = GetReplicateCheckpointResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_streaming_proto_msgTypes[35] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetReplicateCheckpointResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetReplicateCheckpointResponse) ProtoMessage() {} + +func (x *GetReplicateCheckpointResponse) ProtoReflect() protoreflect.Message { + mi := &file_streaming_proto_msgTypes[35] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetReplicateCheckpointResponse.ProtoReflect.Descriptor instead. +func (*GetReplicateCheckpointResponse) Descriptor() ([]byte, []int) { + return file_streaming_proto_rawDescGZIP(), []int{35} +} + +func (x *GetReplicateCheckpointResponse) GetCheckpoint() *commonpb.ReplicateCheckpoint { + if x != nil { + return x.Checkpoint + } + return nil +} + // ProduceRequest is the request of the Produce RPC. // Channel name will be passthrough in the header of stream bu not in the // request body. @@ -2225,7 +2540,7 @@ type ProduceRequest struct { func (x *ProduceRequest) Reset() { *x = ProduceRequest{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[30] + mi := &file_streaming_proto_msgTypes[36] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2238,7 +2553,7 @@ func (x *ProduceRequest) String() string { func (*ProduceRequest) ProtoMessage() {} func (x *ProduceRequest) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[30] + mi := &file_streaming_proto_msgTypes[36] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2251,7 +2566,7 @@ func (x *ProduceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ProduceRequest.ProtoReflect.Descriptor instead. func (*ProduceRequest) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{30} + return file_streaming_proto_rawDescGZIP(), []int{36} } func (m *ProduceRequest) GetRequest() isProduceRequest_Request { @@ -2304,7 +2619,7 @@ type CreateProducerRequest struct { func (x *CreateProducerRequest) Reset() { *x = CreateProducerRequest{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[31] + mi := &file_streaming_proto_msgTypes[37] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2317,7 +2632,7 @@ func (x *CreateProducerRequest) String() string { func (*CreateProducerRequest) ProtoMessage() {} func (x *CreateProducerRequest) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[31] + mi := &file_streaming_proto_msgTypes[37] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2330,7 +2645,7 @@ func (x *CreateProducerRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateProducerRequest.ProtoReflect.Descriptor instead. func (*CreateProducerRequest) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{31} + return file_streaming_proto_rawDescGZIP(), []int{37} } func (x *CreateProducerRequest) GetPchannel() *PChannelInfo { @@ -2353,7 +2668,7 @@ type ProduceMessageRequest struct { func (x *ProduceMessageRequest) Reset() { *x = ProduceMessageRequest{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[32] + mi := &file_streaming_proto_msgTypes[38] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2366,7 +2681,7 @@ func (x *ProduceMessageRequest) String() string { func (*ProduceMessageRequest) ProtoMessage() {} func (x *ProduceMessageRequest) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[32] + mi := &file_streaming_proto_msgTypes[38] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2379,7 +2694,7 @@ func (x *ProduceMessageRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ProduceMessageRequest.ProtoReflect.Descriptor instead. func (*ProduceMessageRequest) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{32} + return file_streaming_proto_rawDescGZIP(), []int{38} } func (x *ProduceMessageRequest) GetRequestId() int64 { @@ -2407,7 +2722,7 @@ type CloseProducerRequest struct { func (x *CloseProducerRequest) Reset() { *x = CloseProducerRequest{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[33] + mi := &file_streaming_proto_msgTypes[39] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2420,7 +2735,7 @@ func (x *CloseProducerRequest) String() string { func (*CloseProducerRequest) ProtoMessage() {} func (x *CloseProducerRequest) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[33] + mi := &file_streaming_proto_msgTypes[39] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2433,7 +2748,7 @@ func (x *CloseProducerRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CloseProducerRequest.ProtoReflect.Descriptor instead. func (*CloseProducerRequest) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{33} + return file_streaming_proto_rawDescGZIP(), []int{39} } // ProduceResponse is the response of the Produce RPC. @@ -2453,7 +2768,7 @@ type ProduceResponse struct { func (x *ProduceResponse) Reset() { *x = ProduceResponse{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[34] + mi := &file_streaming_proto_msgTypes[40] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2466,7 +2781,7 @@ func (x *ProduceResponse) String() string { func (*ProduceResponse) ProtoMessage() {} func (x *ProduceResponse) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[34] + mi := &file_streaming_proto_msgTypes[40] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2479,7 +2794,7 @@ func (x *ProduceResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ProduceResponse.ProtoReflect.Descriptor instead. func (*ProduceResponse) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{34} + return file_streaming_proto_rawDescGZIP(), []int{40} } func (m *ProduceResponse) GetResponse() isProduceResponse_Response { @@ -2538,6 +2853,7 @@ type CreateProducerResponse struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields + // Deprecated: Marked as deprecated in streaming.proto. WalName string `protobuf:"bytes,1,opt,name=wal_name,json=walName,proto3" json:"wal_name,omitempty"` // wal name at server side. ProducerServerId int64 `protobuf:"varint,2,opt,name=producer_server_id,json=producerServerId,proto3" json:"producer_server_id,omitempty"` // A unique producer server id on streamingnode } @@ -2545,7 +2861,7 @@ type CreateProducerResponse struct { func (x *CreateProducerResponse) Reset() { *x = CreateProducerResponse{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[35] + mi := &file_streaming_proto_msgTypes[41] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2558,7 +2874,7 @@ func (x *CreateProducerResponse) String() string { func (*CreateProducerResponse) ProtoMessage() {} func (x *CreateProducerResponse) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[35] + mi := &file_streaming_proto_msgTypes[41] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2571,9 +2887,10 @@ func (x *CreateProducerResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateProducerResponse.ProtoReflect.Descriptor instead. func (*CreateProducerResponse) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{35} + return file_streaming_proto_rawDescGZIP(), []int{41} } +// Deprecated: Marked as deprecated in streaming.proto. func (x *CreateProducerResponse) GetWalName() string { if x != nil { return x.WalName @@ -2605,7 +2922,7 @@ type ProduceMessageResponse struct { func (x *ProduceMessageResponse) Reset() { *x = ProduceMessageResponse{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[36] + mi := &file_streaming_proto_msgTypes[42] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2618,7 +2935,7 @@ func (x *ProduceMessageResponse) String() string { func (*ProduceMessageResponse) ProtoMessage() {} func (x *ProduceMessageResponse) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[36] + mi := &file_streaming_proto_msgTypes[42] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2631,7 +2948,7 @@ func (x *ProduceMessageResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ProduceMessageResponse.ProtoReflect.Descriptor instead. func (*ProduceMessageResponse) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{36} + return file_streaming_proto_rawDescGZIP(), []int{42} } func (x *ProduceMessageResponse) GetRequestId() int64 { @@ -2685,7 +3002,7 @@ type ProduceMessageResponseResult struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Id *messagespb.MessageID `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` // the offset of the message in the channel. + Id *commonpb.MessageID `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` // the offset of the message in the channel. Timetick uint64 `protobuf:"varint,2,opt,name=timetick,proto3" json:"timetick,omitempty"` // the timetick of that message sent. TxnContext *messagespb.TxnContext `protobuf:"bytes,3,opt,name=txnContext,proto3" json:"txnContext,omitempty"` // the txn context of the message. Extra *anypb.Any `protobuf:"bytes,4,opt,name=extra,proto3" json:"extra,omitempty"` // the extra message. @@ -2694,7 +3011,7 @@ type ProduceMessageResponseResult struct { func (x *ProduceMessageResponseResult) Reset() { *x = ProduceMessageResponseResult{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[37] + mi := &file_streaming_proto_msgTypes[43] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2707,7 +3024,7 @@ func (x *ProduceMessageResponseResult) String() string { func (*ProduceMessageResponseResult) ProtoMessage() {} func (x *ProduceMessageResponseResult) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[37] + mi := &file_streaming_proto_msgTypes[43] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2720,10 +3037,10 @@ func (x *ProduceMessageResponseResult) ProtoReflect() protoreflect.Message { // Deprecated: Use ProduceMessageResponseResult.ProtoReflect.Descriptor instead. func (*ProduceMessageResponseResult) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{37} + return file_streaming_proto_rawDescGZIP(), []int{43} } -func (x *ProduceMessageResponseResult) GetId() *messagespb.MessageID { +func (x *ProduceMessageResponseResult) GetId() *commonpb.MessageID { if x != nil { return x.Id } @@ -2761,7 +3078,7 @@ type CloseProducerResponse struct { func (x *CloseProducerResponse) Reset() { *x = CloseProducerResponse{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[38] + mi := &file_streaming_proto_msgTypes[44] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2774,7 +3091,7 @@ func (x *CloseProducerResponse) String() string { func (*CloseProducerResponse) ProtoMessage() {} func (x *CloseProducerResponse) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[38] + mi := &file_streaming_proto_msgTypes[44] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2787,7 +3104,7 @@ func (x *CloseProducerResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CloseProducerResponse.ProtoReflect.Descriptor instead. func (*CloseProducerResponse) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{38} + return file_streaming_proto_rawDescGZIP(), []int{44} } // ConsumeRequest is the request of the Consume RPC. @@ -2809,7 +3126,7 @@ type ConsumeRequest struct { func (x *ConsumeRequest) Reset() { *x = ConsumeRequest{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[39] + mi := &file_streaming_proto_msgTypes[45] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2822,7 +3139,7 @@ func (x *ConsumeRequest) String() string { func (*ConsumeRequest) ProtoMessage() {} func (x *ConsumeRequest) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[39] + mi := &file_streaming_proto_msgTypes[45] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2835,7 +3152,7 @@ func (x *ConsumeRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ConsumeRequest.ProtoReflect.Descriptor instead. func (*ConsumeRequest) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{39} + return file_streaming_proto_rawDescGZIP(), []int{45} } func (m *ConsumeRequest) GetRequest() isConsumeRequest_Request { @@ -2912,7 +3229,7 @@ type CloseConsumerRequest struct { func (x *CloseConsumerRequest) Reset() { *x = CloseConsumerRequest{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[40] + mi := &file_streaming_proto_msgTypes[46] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2925,7 +3242,7 @@ func (x *CloseConsumerRequest) String() string { func (*CloseConsumerRequest) ProtoMessage() {} func (x *CloseConsumerRequest) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[40] + mi := &file_streaming_proto_msgTypes[46] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2938,7 +3255,7 @@ func (x *CloseConsumerRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CloseConsumerRequest.ProtoReflect.Descriptor instead. func (*CloseConsumerRequest) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{40} + return file_streaming_proto_rawDescGZIP(), []int{46} } // CreateConsumerRequest is the request of the CreateConsumer RPC. @@ -2954,7 +3271,7 @@ type CreateConsumerRequest struct { func (x *CreateConsumerRequest) Reset() { *x = CreateConsumerRequest{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[41] + mi := &file_streaming_proto_msgTypes[47] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2967,7 +3284,7 @@ func (x *CreateConsumerRequest) String() string { func (*CreateConsumerRequest) ProtoMessage() {} func (x *CreateConsumerRequest) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[41] + mi := &file_streaming_proto_msgTypes[47] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2980,7 +3297,7 @@ func (x *CreateConsumerRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateConsumerRequest.ProtoReflect.Descriptor instead. func (*CreateConsumerRequest) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{41} + return file_streaming_proto_rawDescGZIP(), []int{47} } func (x *CreateConsumerRequest) GetPchannel() *PChannelInfo { @@ -3001,7 +3318,7 @@ type CreateVChannelConsumersRequest struct { func (x *CreateVChannelConsumersRequest) Reset() { *x = CreateVChannelConsumersRequest{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[42] + mi := &file_streaming_proto_msgTypes[48] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3014,7 +3331,7 @@ func (x *CreateVChannelConsumersRequest) String() string { func (*CreateVChannelConsumersRequest) ProtoMessage() {} func (x *CreateVChannelConsumersRequest) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[42] + mi := &file_streaming_proto_msgTypes[48] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3027,7 +3344,7 @@ func (x *CreateVChannelConsumersRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateVChannelConsumersRequest.ProtoReflect.Descriptor instead. func (*CreateVChannelConsumersRequest) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{42} + return file_streaming_proto_rawDescGZIP(), []int{48} } func (x *CreateVChannelConsumersRequest) GetCreateVchannels() []*CreateVChannelConsumerRequest { @@ -3052,7 +3369,7 @@ type CreateVChannelConsumerRequest struct { func (x *CreateVChannelConsumerRequest) Reset() { *x = CreateVChannelConsumerRequest{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[43] + mi := &file_streaming_proto_msgTypes[49] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3065,7 +3382,7 @@ func (x *CreateVChannelConsumerRequest) String() string { func (*CreateVChannelConsumerRequest) ProtoMessage() {} func (x *CreateVChannelConsumerRequest) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[43] + mi := &file_streaming_proto_msgTypes[49] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3078,7 +3395,7 @@ func (x *CreateVChannelConsumerRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateVChannelConsumerRequest.ProtoReflect.Descriptor instead. func (*CreateVChannelConsumerRequest) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{43} + return file_streaming_proto_rawDescGZIP(), []int{49} } func (x *CreateVChannelConsumerRequest) GetVchannel() string { @@ -3114,7 +3431,7 @@ type CreateVChannelConsumersResponse struct { func (x *CreateVChannelConsumersResponse) Reset() { *x = CreateVChannelConsumersResponse{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[44] + mi := &file_streaming_proto_msgTypes[50] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3127,7 +3444,7 @@ func (x *CreateVChannelConsumersResponse) String() string { func (*CreateVChannelConsumersResponse) ProtoMessage() {} func (x *CreateVChannelConsumersResponse) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[44] + mi := &file_streaming_proto_msgTypes[50] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3140,7 +3457,7 @@ func (x *CreateVChannelConsumersResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateVChannelConsumersResponse.ProtoReflect.Descriptor instead. func (*CreateVChannelConsumersResponse) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{44} + return file_streaming_proto_rawDescGZIP(), []int{50} } func (x *CreateVChannelConsumersResponse) GetCreateVchannels() []*CreateVChannelConsumerResponse { @@ -3167,7 +3484,7 @@ type CreateVChannelConsumerResponse struct { func (x *CreateVChannelConsumerResponse) Reset() { *x = CreateVChannelConsumerResponse{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[45] + mi := &file_streaming_proto_msgTypes[51] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3180,7 +3497,7 @@ func (x *CreateVChannelConsumerResponse) String() string { func (*CreateVChannelConsumerResponse) ProtoMessage() {} func (x *CreateVChannelConsumerResponse) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[45] + mi := &file_streaming_proto_msgTypes[51] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3193,7 +3510,7 @@ func (x *CreateVChannelConsumerResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateVChannelConsumerResponse.ProtoReflect.Descriptor instead. func (*CreateVChannelConsumerResponse) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{45} + return file_streaming_proto_rawDescGZIP(), []int{51} } func (m *CreateVChannelConsumerResponse) GetResponse() isCreateVChannelConsumerResponse_Response { @@ -3245,7 +3562,7 @@ type CloseVChannelConsumerRequest struct { func (x *CloseVChannelConsumerRequest) Reset() { *x = CloseVChannelConsumerRequest{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[46] + mi := &file_streaming_proto_msgTypes[52] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3258,7 +3575,7 @@ func (x *CloseVChannelConsumerRequest) String() string { func (*CloseVChannelConsumerRequest) ProtoMessage() {} func (x *CloseVChannelConsumerRequest) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[46] + mi := &file_streaming_proto_msgTypes[52] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3271,7 +3588,7 @@ func (x *CloseVChannelConsumerRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CloseVChannelConsumerRequest.ProtoReflect.Descriptor instead. func (*CloseVChannelConsumerRequest) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{46} + return file_streaming_proto_rawDescGZIP(), []int{52} } func (x *CloseVChannelConsumerRequest) GetConsumerId() int64 { @@ -3294,7 +3611,7 @@ type CloseVChannelConsumerResponse struct { func (x *CloseVChannelConsumerResponse) Reset() { *x = CloseVChannelConsumerResponse{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[47] + mi := &file_streaming_proto_msgTypes[53] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3307,7 +3624,7 @@ func (x *CloseVChannelConsumerResponse) String() string { func (*CloseVChannelConsumerResponse) ProtoMessage() {} func (x *CloseVChannelConsumerResponse) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[47] + mi := &file_streaming_proto_msgTypes[53] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3320,7 +3637,7 @@ func (x *CloseVChannelConsumerResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CloseVChannelConsumerResponse.ProtoReflect.Descriptor instead. func (*CloseVChannelConsumerResponse) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{47} + return file_streaming_proto_rawDescGZIP(), []int{53} } func (x *CloseVChannelConsumerResponse) GetConsumerId() int64 { @@ -3350,7 +3667,7 @@ type ConsumeResponse struct { func (x *ConsumeResponse) Reset() { *x = ConsumeResponse{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[48] + mi := &file_streaming_proto_msgTypes[54] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3363,7 +3680,7 @@ func (x *ConsumeResponse) String() string { func (*ConsumeResponse) ProtoMessage() {} func (x *ConsumeResponse) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[48] + mi := &file_streaming_proto_msgTypes[54] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3376,7 +3693,7 @@ func (x *ConsumeResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ConsumeResponse.ProtoReflect.Descriptor instead. func (*ConsumeResponse) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{48} + return file_streaming_proto_rawDescGZIP(), []int{54} } func (m *ConsumeResponse) GetResponse() isConsumeResponse_Response { @@ -3473,6 +3790,7 @@ type CreateConsumerResponse struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields + // Deprecated: Marked as deprecated in streaming.proto. WalName string `protobuf:"bytes,1,opt,name=wal_name,json=walName,proto3" json:"wal_name,omitempty"` // wal name at server side. // A unique consumer id on streamingnode for this // consumer in streamingnode lifetime. @@ -3482,7 +3800,7 @@ type CreateConsumerResponse struct { func (x *CreateConsumerResponse) Reset() { *x = CreateConsumerResponse{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[49] + mi := &file_streaming_proto_msgTypes[55] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3495,7 +3813,7 @@ func (x *CreateConsumerResponse) String() string { func (*CreateConsumerResponse) ProtoMessage() {} func (x *CreateConsumerResponse) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[49] + mi := &file_streaming_proto_msgTypes[55] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3508,9 +3826,10 @@ func (x *CreateConsumerResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateConsumerResponse.ProtoReflect.Descriptor instead. func (*CreateConsumerResponse) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{49} + return file_streaming_proto_rawDescGZIP(), []int{55} } +// Deprecated: Marked as deprecated in streaming.proto. func (x *CreateConsumerResponse) GetWalName() string { if x != nil { return x.WalName @@ -3530,14 +3849,14 @@ type ConsumeMessageReponse struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - ConsumerId int64 `protobuf:"varint,1,opt,name=consumer_id,json=consumerId,proto3" json:"consumer_id,omitempty"` - Message *messagespb.ImmutableMessage `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"` + ConsumerId int64 `protobuf:"varint,1,opt,name=consumer_id,json=consumerId,proto3" json:"consumer_id,omitempty"` + Message *commonpb.ImmutableMessage `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"` } func (x *ConsumeMessageReponse) Reset() { *x = ConsumeMessageReponse{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[50] + mi := &file_streaming_proto_msgTypes[56] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3550,7 +3869,7 @@ func (x *ConsumeMessageReponse) String() string { func (*ConsumeMessageReponse) ProtoMessage() {} func (x *ConsumeMessageReponse) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[50] + mi := &file_streaming_proto_msgTypes[56] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3563,7 +3882,7 @@ func (x *ConsumeMessageReponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ConsumeMessageReponse.ProtoReflect.Descriptor instead. func (*ConsumeMessageReponse) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{50} + return file_streaming_proto_rawDescGZIP(), []int{56} } func (x *ConsumeMessageReponse) GetConsumerId() int64 { @@ -3573,7 +3892,7 @@ func (x *ConsumeMessageReponse) GetConsumerId() int64 { return 0 } -func (x *ConsumeMessageReponse) GetMessage() *messagespb.ImmutableMessage { +func (x *ConsumeMessageReponse) GetMessage() *commonpb.ImmutableMessage { if x != nil { return x.Message } @@ -3589,7 +3908,7 @@ type CloseConsumerResponse struct { func (x *CloseConsumerResponse) Reset() { *x = CloseConsumerResponse{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[51] + mi := &file_streaming_proto_msgTypes[57] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3602,7 +3921,7 @@ func (x *CloseConsumerResponse) String() string { func (*CloseConsumerResponse) ProtoMessage() {} func (x *CloseConsumerResponse) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[51] + mi := &file_streaming_proto_msgTypes[57] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3615,7 +3934,7 @@ func (x *CloseConsumerResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CloseConsumerResponse.ProtoReflect.Descriptor instead. func (*CloseConsumerResponse) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{51} + return file_streaming_proto_rawDescGZIP(), []int{57} } // StreamingManagerAssignRequest is the request message of Assign RPC. @@ -3630,7 +3949,7 @@ type StreamingNodeManagerAssignRequest struct { func (x *StreamingNodeManagerAssignRequest) Reset() { *x = StreamingNodeManagerAssignRequest{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[52] + mi := &file_streaming_proto_msgTypes[58] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3643,7 +3962,7 @@ func (x *StreamingNodeManagerAssignRequest) String() string { func (*StreamingNodeManagerAssignRequest) ProtoMessage() {} func (x *StreamingNodeManagerAssignRequest) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[52] + mi := &file_streaming_proto_msgTypes[58] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3656,7 +3975,7 @@ func (x *StreamingNodeManagerAssignRequest) ProtoReflect() protoreflect.Message // Deprecated: Use StreamingNodeManagerAssignRequest.ProtoReflect.Descriptor instead. func (*StreamingNodeManagerAssignRequest) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{52} + return file_streaming_proto_rawDescGZIP(), []int{58} } func (x *StreamingNodeManagerAssignRequest) GetPchannel() *PChannelInfo { @@ -3675,7 +3994,7 @@ type StreamingNodeManagerAssignResponse struct { func (x *StreamingNodeManagerAssignResponse) Reset() { *x = StreamingNodeManagerAssignResponse{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[53] + mi := &file_streaming_proto_msgTypes[59] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3688,7 +4007,7 @@ func (x *StreamingNodeManagerAssignResponse) String() string { func (*StreamingNodeManagerAssignResponse) ProtoMessage() {} func (x *StreamingNodeManagerAssignResponse) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[53] + mi := &file_streaming_proto_msgTypes[59] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3701,7 +4020,7 @@ func (x *StreamingNodeManagerAssignResponse) ProtoReflect() protoreflect.Message // Deprecated: Use StreamingNodeManagerAssignResponse.ProtoReflect.Descriptor instead. func (*StreamingNodeManagerAssignResponse) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{53} + return file_streaming_proto_rawDescGZIP(), []int{59} } type StreamingNodeManagerRemoveRequest struct { @@ -3715,7 +4034,7 @@ type StreamingNodeManagerRemoveRequest struct { func (x *StreamingNodeManagerRemoveRequest) Reset() { *x = StreamingNodeManagerRemoveRequest{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[54] + mi := &file_streaming_proto_msgTypes[60] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3728,7 +4047,7 @@ func (x *StreamingNodeManagerRemoveRequest) String() string { func (*StreamingNodeManagerRemoveRequest) ProtoMessage() {} func (x *StreamingNodeManagerRemoveRequest) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[54] + mi := &file_streaming_proto_msgTypes[60] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3741,7 +4060,7 @@ func (x *StreamingNodeManagerRemoveRequest) ProtoReflect() protoreflect.Message // Deprecated: Use StreamingNodeManagerRemoveRequest.ProtoReflect.Descriptor instead. func (*StreamingNodeManagerRemoveRequest) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{54} + return file_streaming_proto_rawDescGZIP(), []int{60} } func (x *StreamingNodeManagerRemoveRequest) GetPchannel() *PChannelInfo { @@ -3760,7 +4079,7 @@ type StreamingNodeManagerRemoveResponse struct { func (x *StreamingNodeManagerRemoveResponse) Reset() { *x = StreamingNodeManagerRemoveResponse{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[55] + mi := &file_streaming_proto_msgTypes[61] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3773,7 +4092,7 @@ func (x *StreamingNodeManagerRemoveResponse) String() string { func (*StreamingNodeManagerRemoveResponse) ProtoMessage() {} func (x *StreamingNodeManagerRemoveResponse) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[55] + mi := &file_streaming_proto_msgTypes[61] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3786,7 +4105,7 @@ func (x *StreamingNodeManagerRemoveResponse) ProtoReflect() protoreflect.Message // Deprecated: Use StreamingNodeManagerRemoveResponse.ProtoReflect.Descriptor instead. func (*StreamingNodeManagerRemoveResponse) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{55} + return file_streaming_proto_rawDescGZIP(), []int{61} } type StreamingNodeManagerCollectStatusRequest struct { @@ -3798,7 +4117,7 @@ type StreamingNodeManagerCollectStatusRequest struct { func (x *StreamingNodeManagerCollectStatusRequest) Reset() { *x = StreamingNodeManagerCollectStatusRequest{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[56] + mi := &file_streaming_proto_msgTypes[62] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3811,7 +4130,7 @@ func (x *StreamingNodeManagerCollectStatusRequest) String() string { func (*StreamingNodeManagerCollectStatusRequest) ProtoMessage() {} func (x *StreamingNodeManagerCollectStatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[56] + mi := &file_streaming_proto_msgTypes[62] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3824,7 +4143,7 @@ func (x *StreamingNodeManagerCollectStatusRequest) ProtoReflect() protoreflect.M // Deprecated: Use StreamingNodeManagerCollectStatusRequest.ProtoReflect.Descriptor instead. func (*StreamingNodeManagerCollectStatusRequest) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{56} + return file_streaming_proto_rawDescGZIP(), []int{62} } type StreamingNodeMetrics struct { @@ -3838,7 +4157,7 @@ type StreamingNodeMetrics struct { func (x *StreamingNodeMetrics) Reset() { *x = StreamingNodeMetrics{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[57] + mi := &file_streaming_proto_msgTypes[63] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3851,7 +4170,7 @@ func (x *StreamingNodeMetrics) String() string { func (*StreamingNodeMetrics) ProtoMessage() {} func (x *StreamingNodeMetrics) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[57] + mi := &file_streaming_proto_msgTypes[63] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3864,7 +4183,7 @@ func (x *StreamingNodeMetrics) ProtoReflect() protoreflect.Message { // Deprecated: Use StreamingNodeMetrics.ProtoReflect.Descriptor instead. func (*StreamingNodeMetrics) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{57} + return file_streaming_proto_rawDescGZIP(), []int{63} } func (x *StreamingNodeMetrics) GetWals() []*StreamingNodeWALMetrics { @@ -3890,7 +4209,7 @@ type StreamingNodeWALMetrics struct { func (x *StreamingNodeWALMetrics) Reset() { *x = StreamingNodeWALMetrics{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[58] + mi := &file_streaming_proto_msgTypes[64] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3903,7 +4222,7 @@ func (x *StreamingNodeWALMetrics) String() string { func (*StreamingNodeWALMetrics) ProtoMessage() {} func (x *StreamingNodeWALMetrics) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[58] + mi := &file_streaming_proto_msgTypes[64] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3916,7 +4235,7 @@ func (x *StreamingNodeWALMetrics) ProtoReflect() protoreflect.Message { // Deprecated: Use StreamingNodeWALMetrics.ProtoReflect.Descriptor instead. func (*StreamingNodeWALMetrics) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{58} + return file_streaming_proto_rawDescGZIP(), []int{64} } func (x *StreamingNodeWALMetrics) GetInfo() *PChannelInfo { @@ -3975,7 +4294,7 @@ type StreamingNodeRWWALMetrics struct { func (x *StreamingNodeRWWALMetrics) Reset() { *x = StreamingNodeRWWALMetrics{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[59] + mi := &file_streaming_proto_msgTypes[65] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3988,7 +4307,7 @@ func (x *StreamingNodeRWWALMetrics) String() string { func (*StreamingNodeRWWALMetrics) ProtoMessage() {} func (x *StreamingNodeRWWALMetrics) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[59] + mi := &file_streaming_proto_msgTypes[65] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4001,7 +4320,7 @@ func (x *StreamingNodeRWWALMetrics) ProtoReflect() protoreflect.Message { // Deprecated: Use StreamingNodeRWWALMetrics.ProtoReflect.Descriptor instead. func (*StreamingNodeRWWALMetrics) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{59} + return file_streaming_proto_rawDescGZIP(), []int{65} } func (x *StreamingNodeRWWALMetrics) GetMvccTimeTick() uint64 { @@ -4027,7 +4346,7 @@ type StreamingNodeROWALMetrics struct { func (x *StreamingNodeROWALMetrics) Reset() { *x = StreamingNodeROWALMetrics{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[60] + mi := &file_streaming_proto_msgTypes[66] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4040,7 +4359,7 @@ func (x *StreamingNodeROWALMetrics) String() string { func (*StreamingNodeROWALMetrics) ProtoMessage() {} func (x *StreamingNodeROWALMetrics) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[60] + mi := &file_streaming_proto_msgTypes[66] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4053,7 +4372,7 @@ func (x *StreamingNodeROWALMetrics) ProtoReflect() protoreflect.Message { // Deprecated: Use StreamingNodeROWALMetrics.ProtoReflect.Descriptor instead. func (*StreamingNodeROWALMetrics) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{60} + return file_streaming_proto_rawDescGZIP(), []int{66} } type StreamingNodeManagerCollectStatusResponse struct { @@ -4067,7 +4386,7 @@ type StreamingNodeManagerCollectStatusResponse struct { func (x *StreamingNodeManagerCollectStatusResponse) Reset() { *x = StreamingNodeManagerCollectStatusResponse{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[61] + mi := &file_streaming_proto_msgTypes[67] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4080,7 +4399,7 @@ func (x *StreamingNodeManagerCollectStatusResponse) String() string { func (*StreamingNodeManagerCollectStatusResponse) ProtoMessage() {} func (x *StreamingNodeManagerCollectStatusResponse) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[61] + mi := &file_streaming_proto_msgTypes[67] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4093,7 +4412,7 @@ func (x *StreamingNodeManagerCollectStatusResponse) ProtoReflect() protoreflect. // Deprecated: Use StreamingNodeManagerCollectStatusResponse.ProtoReflect.Descriptor instead. func (*StreamingNodeManagerCollectStatusResponse) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{61} + return file_streaming_proto_rawDescGZIP(), []int{67} } func (x *StreamingNodeManagerCollectStatusResponse) GetMetrics() *StreamingNodeMetrics { @@ -4123,7 +4442,7 @@ type VChannelMeta struct { func (x *VChannelMeta) Reset() { *x = VChannelMeta{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[62] + mi := &file_streaming_proto_msgTypes[68] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4136,7 +4455,7 @@ func (x *VChannelMeta) String() string { func (*VChannelMeta) ProtoMessage() {} func (x *VChannelMeta) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[62] + mi := &file_streaming_proto_msgTypes[68] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4149,7 +4468,7 @@ func (x *VChannelMeta) ProtoReflect() protoreflect.Message { // Deprecated: Use VChannelMeta.ProtoReflect.Descriptor instead. func (*VChannelMeta) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{62} + return file_streaming_proto_rawDescGZIP(), []int{68} } func (x *VChannelMeta) GetVchannel() string { @@ -4194,7 +4513,7 @@ type CollectionInfoOfVChannel struct { func (x *CollectionInfoOfVChannel) Reset() { *x = CollectionInfoOfVChannel{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[63] + mi := &file_streaming_proto_msgTypes[69] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4207,7 +4526,7 @@ func (x *CollectionInfoOfVChannel) String() string { func (*CollectionInfoOfVChannel) ProtoMessage() {} func (x *CollectionInfoOfVChannel) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[63] + mi := &file_streaming_proto_msgTypes[69] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4220,7 +4539,7 @@ func (x *CollectionInfoOfVChannel) ProtoReflect() protoreflect.Message { // Deprecated: Use CollectionInfoOfVChannel.ProtoReflect.Descriptor instead. func (*CollectionInfoOfVChannel) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{63} + return file_streaming_proto_rawDescGZIP(), []int{69} } func (x *CollectionInfoOfVChannel) GetCollectionId() int64 { @@ -4258,7 +4577,7 @@ type CollectionSchemaOfVChannel struct { func (x *CollectionSchemaOfVChannel) Reset() { *x = CollectionSchemaOfVChannel{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[64] + mi := &file_streaming_proto_msgTypes[70] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4271,7 +4590,7 @@ func (x *CollectionSchemaOfVChannel) String() string { func (*CollectionSchemaOfVChannel) ProtoMessage() {} func (x *CollectionSchemaOfVChannel) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[64] + mi := &file_streaming_proto_msgTypes[70] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4284,7 +4603,7 @@ func (x *CollectionSchemaOfVChannel) ProtoReflect() protoreflect.Message { // Deprecated: Use CollectionSchemaOfVChannel.ProtoReflect.Descriptor instead. func (*CollectionSchemaOfVChannel) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{64} + return file_streaming_proto_rawDescGZIP(), []int{70} } func (x *CollectionSchemaOfVChannel) GetSchema() *schemapb.CollectionSchema { @@ -4320,7 +4639,7 @@ type PartitionInfoOfVChannel struct { func (x *PartitionInfoOfVChannel) Reset() { *x = PartitionInfoOfVChannel{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[65] + mi := &file_streaming_proto_msgTypes[71] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4333,7 +4652,7 @@ func (x *PartitionInfoOfVChannel) String() string { func (*PartitionInfoOfVChannel) ProtoMessage() {} func (x *PartitionInfoOfVChannel) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[65] + mi := &file_streaming_proto_msgTypes[71] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4346,7 +4665,7 @@ func (x *PartitionInfoOfVChannel) ProtoReflect() protoreflect.Message { // Deprecated: Use PartitionInfoOfVChannel.ProtoReflect.Descriptor instead. func (*PartitionInfoOfVChannel) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{65} + return file_streaming_proto_rawDescGZIP(), []int{71} } func (x *PartitionInfoOfVChannel) GetPartitionId() int64 { @@ -4382,7 +4701,7 @@ type SegmentAssignmentMeta struct { func (x *SegmentAssignmentMeta) Reset() { *x = SegmentAssignmentMeta{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[66] + mi := &file_streaming_proto_msgTypes[72] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4395,7 +4714,7 @@ func (x *SegmentAssignmentMeta) String() string { func (*SegmentAssignmentMeta) ProtoMessage() {} func (x *SegmentAssignmentMeta) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[66] + mi := &file_streaming_proto_msgTypes[72] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4408,7 +4727,7 @@ func (x *SegmentAssignmentMeta) ProtoReflect() protoreflect.Message { // Deprecated: Use SegmentAssignmentMeta.ProtoReflect.Descriptor instead. func (*SegmentAssignmentMeta) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{66} + return file_streaming_proto_rawDescGZIP(), []int{72} } func (x *SegmentAssignmentMeta) GetCollectionId() int64 { @@ -4487,7 +4806,7 @@ type SegmentAssignmentStat struct { func (x *SegmentAssignmentStat) Reset() { *x = SegmentAssignmentStat{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[67] + mi := &file_streaming_proto_msgTypes[73] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4500,7 +4819,7 @@ func (x *SegmentAssignmentStat) String() string { func (*SegmentAssignmentStat) ProtoMessage() {} func (x *SegmentAssignmentStat) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[67] + mi := &file_streaming_proto_msgTypes[73] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4513,7 +4832,7 @@ func (x *SegmentAssignmentStat) ProtoReflect() protoreflect.Message { // Deprecated: Use SegmentAssignmentStat.ProtoReflect.Descriptor instead. func (*SegmentAssignmentStat) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{67} + return file_streaming_proto_rawDescGZIP(), []int{73} } func (x *SegmentAssignmentStat) GetMaxBinarySize() uint64 { @@ -4585,7 +4904,7 @@ type WALCheckpoint struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - MessageId *messagespb.MessageID `protobuf:"bytes,1,opt,name=message_id,json=messageId,proto3" json:"message_id,omitempty"` // From here to recover all uncommited info. + MessageId *commonpb.MessageID `protobuf:"bytes,1,opt,name=message_id,json=messageId,proto3" json:"message_id,omitempty"` // From here to recover all uncommited info. // e.g., primary key index, segment assignment info, vchannel info... // because current data path flush is slow, and managed by the coordinator, current current is not apply to it. // @@ -4593,12 +4912,15 @@ type WALCheckpoint struct { TimeTick uint64 `protobuf:"varint,2,opt,name=time_tick,json=timeTick,proto3" json:"time_tick,omitempty"` // The timetick of checkpoint, keep consistecy with message_id. // It's a hint for easier debugging. RecoveryMagic int64 `protobuf:"varint,3,opt,name=recovery_magic,json=recoveryMagic,proto3" json:"recovery_magic,omitempty"` // The recovery version of the checkpoint, it's used to hint the future recovery info upgrading. + // The wal name of the checkpoint. + ReplicateConfig *commonpb.ReplicateConfiguration `protobuf:"bytes,4,opt,name=replicate_config,json=replicateConfig,proto3" json:"replicate_config,omitempty"` // if the wal join a replicated clusters, the replicate config is not null, + ReplicateCheckpoint *commonpb.ReplicateCheckpoint `protobuf:"bytes,5,opt,name=replicate_checkpoint,json=replicateCheckpoint,proto3" json:"replicate_checkpoint,omitempty"` // if the wal is replicated from remote cluster, the checkpoint is not null, } func (x *WALCheckpoint) Reset() { *x = WALCheckpoint{} if protoimpl.UnsafeEnabled { - mi := &file_streaming_proto_msgTypes[68] + mi := &file_streaming_proto_msgTypes[74] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4611,7 +4933,7 @@ func (x *WALCheckpoint) String() string { func (*WALCheckpoint) ProtoMessage() {} func (x *WALCheckpoint) ProtoReflect() protoreflect.Message { - mi := &file_streaming_proto_msgTypes[68] + mi := &file_streaming_proto_msgTypes[74] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4624,10 +4946,10 @@ func (x *WALCheckpoint) ProtoReflect() protoreflect.Message { // Deprecated: Use WALCheckpoint.ProtoReflect.Descriptor instead. func (*WALCheckpoint) Descriptor() ([]byte, []int) { - return file_streaming_proto_rawDescGZIP(), []int{68} + return file_streaming_proto_rawDescGZIP(), []int{74} } -func (x *WALCheckpoint) GetMessageId() *messagespb.MessageID { +func (x *WALCheckpoint) GetMessageId() *commonpb.MessageID { if x != nil { return x.MessageId } @@ -4648,6 +4970,147 @@ func (x *WALCheckpoint) GetRecoveryMagic() int64 { return 0 } +func (x *WALCheckpoint) GetReplicateConfig() *commonpb.ReplicateConfiguration { + if x != nil { + return x.ReplicateConfig + } + return nil +} + +func (x *WALCheckpoint) GetReplicateCheckpoint() *commonpb.ReplicateCheckpoint { + if x != nil { + return x.ReplicateCheckpoint + } + return nil +} + +// ReplicateConfigurationMeta is the replicate configuration of the wal. +type ReplicateConfigurationMeta struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ReplicateConfiguration *commonpb.ReplicateConfiguration `protobuf:"bytes,1,opt,name=replicate_configuration,json=replicateConfiguration,proto3" json:"replicate_configuration,omitempty"` + AckedResult *AckedResult `protobuf:"bytes,2,opt,name=acked_result,json=ackedResult,proto3" json:"acked_result,omitempty"` // a acked helper to help managing the consuming of PutReplicateConfigMessageV2 message at coordinator. +} + +func (x *ReplicateConfigurationMeta) Reset() { + *x = ReplicateConfigurationMeta{} + if protoimpl.UnsafeEnabled { + mi := &file_streaming_proto_msgTypes[75] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ReplicateConfigurationMeta) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReplicateConfigurationMeta) ProtoMessage() {} + +func (x *ReplicateConfigurationMeta) ProtoReflect() protoreflect.Message { + mi := &file_streaming_proto_msgTypes[75] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ReplicateConfigurationMeta.ProtoReflect.Descriptor instead. +func (*ReplicateConfigurationMeta) Descriptor() ([]byte, []int) { + return file_streaming_proto_rawDescGZIP(), []int{75} +} + +func (x *ReplicateConfigurationMeta) GetReplicateConfiguration() *commonpb.ReplicateConfiguration { + if x != nil { + return x.ReplicateConfiguration + } + return nil +} + +func (x *ReplicateConfigurationMeta) GetAckedResult() *AckedResult { + if x != nil { + return x.AckedResult + } + return nil +} + +type ReplicatePChannelMeta struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SourceChannelName string `protobuf:"bytes,1,opt,name=source_channel_name,json=sourceChannelName,proto3" json:"source_channel_name,omitempty"` + TargetChannelName string `protobuf:"bytes,2,opt,name=target_channel_name,json=targetChannelName,proto3" json:"target_channel_name,omitempty"` + TargetCluster *commonpb.MilvusCluster `protobuf:"bytes,3,opt,name=target_cluster,json=targetCluster,proto3" json:"target_cluster,omitempty"` + InitializedCheckpoint *commonpb.ReplicateCheckpoint `protobuf:"bytes,4,opt,name=initialized_checkpoint,json=initializedCheckpoint,proto3" json:"initialized_checkpoint,omitempty"` +} + +func (x *ReplicatePChannelMeta) Reset() { + *x = ReplicatePChannelMeta{} + if protoimpl.UnsafeEnabled { + mi := &file_streaming_proto_msgTypes[76] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ReplicatePChannelMeta) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReplicatePChannelMeta) ProtoMessage() {} + +func (x *ReplicatePChannelMeta) ProtoReflect() protoreflect.Message { + mi := &file_streaming_proto_msgTypes[76] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ReplicatePChannelMeta.ProtoReflect.Descriptor instead. +func (*ReplicatePChannelMeta) Descriptor() ([]byte, []int) { + return file_streaming_proto_rawDescGZIP(), []int{76} +} + +func (x *ReplicatePChannelMeta) GetSourceChannelName() string { + if x != nil { + return x.SourceChannelName + } + return "" +} + +func (x *ReplicatePChannelMeta) GetTargetChannelName() string { + if x != nil { + return x.TargetChannelName + } + return "" +} + +func (x *ReplicatePChannelMeta) GetTargetCluster() *commonpb.MilvusCluster { + if x != nil { + return x.TargetCluster + } + return nil +} + +func (x *ReplicatePChannelMeta) GetInitializedCheckpoint() *commonpb.ReplicateCheckpoint { + if x != nil { + return x.InitializedCheckpoint + } + return nil +} + var File_streaming_proto protoreflect.FileDescriptor var file_streaming_proto_rawDesc = []byte{ @@ -4655,201 +5118,239 @@ var file_streaming_proto_rawDesc = []byte{ 0x6f, 0x12, 0x16, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x1a, 0x10, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x0e, 0x6d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x0c, 0x6d, 0x69, 0x6c, - 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x0c, 0x73, 0x63, 0x68, 0x65, 0x6d, - 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, - 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x22, 0x83, 0x01, 0x0a, 0x0c, 0x50, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x6e, - 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, 0x72, 0x6d, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x74, 0x65, 0x72, 0x6d, 0x12, 0x4b, 0x0a, 0x0b, 0x61, 0x63, - 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, - 0x2a, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, - 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, - 0x6c, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x0a, 0x61, 0x63, 0x63, - 0x65, 0x73, 0x73, 0x4d, 0x6f, 0x64, 0x65, 0x22, 0xb7, 0x01, 0x0a, 0x15, 0x50, 0x43, 0x68, 0x61, - 0x6e, 0x6e, 0x65, 0x6c, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x4c, 0x6f, - 0x67, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, 0x72, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x04, 0x74, 0x65, 0x72, 0x6d, 0x12, 0x3d, 0x0a, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x53, 0x74, 0x72, - 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, - 0x6e, 0x6f, 0x64, 0x65, 0x12, 0x4b, 0x0a, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6d, - 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2a, 0x2e, 0x6d, 0x69, 0x6c, 0x76, - 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, - 0x6e, 0x67, 0x2e, 0x50, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x41, 0x63, 0x63, 0x65, 0x73, - 0x73, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x0a, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4d, 0x6f, 0x64, - 0x65, 0x22, 0xde, 0x02, 0x0a, 0x0c, 0x50, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x4d, 0x65, - 0x74, 0x61, 0x12, 0x3e, 0x0a, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, + 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x0c, 0x63, 0x6f, 0x6d, + 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x0c, 0x6d, 0x69, 0x6c, 0x76, 0x75, + 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x0c, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x20, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x66, + 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, + 0x83, 0x01, 0x0a, 0x0c, 0x50, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x6e, 0x66, 0x6f, + 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, 0x72, 0x6d, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x04, 0x74, 0x65, 0x72, 0x6d, 0x12, 0x4b, 0x0a, 0x0b, 0x61, 0x63, 0x63, 0x65, + 0x73, 0x73, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2a, 0x2e, + 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, + 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x41, + 0x63, 0x63, 0x65, 0x73, 0x73, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x0a, 0x61, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x4d, 0x6f, 0x64, 0x65, 0x22, 0xb7, 0x01, 0x0a, 0x15, 0x50, 0x43, 0x68, 0x61, 0x6e, 0x6e, + 0x65, 0x6c, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x4c, 0x6f, 0x67, 0x12, + 0x12, 0x0a, 0x04, 0x74, 0x65, 0x72, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x74, + 0x65, 0x72, 0x6d, 0x12, 0x3d, 0x0a, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x29, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, + 0x6d, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x6e, 0x6f, + 0x64, 0x65, 0x12, 0x4b, 0x0a, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6d, 0x6f, 0x64, + 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2a, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, + 0x2e, 0x50, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4d, + 0x6f, 0x64, 0x65, 0x52, 0x0a, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4d, 0x6f, 0x64, 0x65, 0x22, + 0xde, 0x02, 0x0a, 0x0c, 0x50, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x4d, 0x65, 0x74, 0x61, + 0x12, 0x3e, 0x0a, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x24, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x43, 0x68, 0x61, 0x6e, + 0x6e, 0x65, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, + 0x12, 0x3d, 0x0a, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, + 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, + 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, + 0x67, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x12, + 0x3f, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x29, + 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, + 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, + 0x4d, 0x65, 0x74, 0x61, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, + 0x12, 0x4b, 0x0a, 0x09, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x18, 0x04, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x43, 0x68, - 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x6e, - 0x65, 0x6c, 0x12, 0x3d, 0x0a, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x29, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, - 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, - 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x6e, 0x6f, 0x64, - 0x65, 0x12, 0x3f, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, - 0x32, 0x29, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, - 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x43, 0x68, 0x61, 0x6e, 0x6e, - 0x65, 0x6c, 0x4d, 0x65, 0x74, 0x61, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, - 0x74, 0x65, 0x12, 0x4b, 0x0a, 0x09, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x18, - 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x50, - 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, - 0x74, 0x4c, 0x6f, 0x67, 0x52, 0x09, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x12, - 0x41, 0x0a, 0x1d, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x61, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x5f, 0x74, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x1a, 0x6c, 0x61, 0x73, 0x74, 0x41, 0x73, 0x73, 0x69, - 0x67, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x53, 0x65, 0x63, 0x6f, 0x6e, - 0x64, 0x73, 0x22, 0x2a, 0x0a, 0x0c, 0x43, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x4d, 0x65, - 0x74, 0x61, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x22, 0x2c, - 0x0a, 0x10, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x56, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x3b, 0x0a, 0x0b, - 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x69, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x67, - 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x67, 0x6c, 0x6f, - 0x62, 0x61, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x05, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x22, 0xbf, 0x01, 0x0a, 0x0d, 0x42, 0x72, - 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x38, 0x0a, 0x07, 0x6d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6d, - 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x73, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x07, 0x6d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x40, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2a, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x42, 0x72, - 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x65, - 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x32, 0x0a, 0x15, 0x61, 0x63, 0x6b, 0x65, 0x64, - 0x5f, 0x76, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x70, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x13, 0x61, 0x63, 0x6b, 0x65, 0x64, 0x56, 0x63, 0x68, - 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x69, 0x74, 0x6d, 0x61, 0x70, 0x22, 0x4c, 0x0a, 0x10, 0x42, - 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x38, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x4c, + 0x6f, 0x67, 0x52, 0x09, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x12, 0x41, 0x0a, + 0x1d, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x61, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x5f, 0x74, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x1a, 0x6c, 0x61, 0x73, 0x74, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, + 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, + 0x22, 0x2a, 0x0a, 0x0c, 0x43, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x4d, 0x65, 0x74, 0x61, + 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x70, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x22, 0x2c, 0x0a, 0x10, + 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x3b, 0x0a, 0x0b, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x69, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x67, 0x6c, 0x6f, + 0x62, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x67, 0x6c, 0x6f, 0x62, 0x61, + 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x05, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x22, 0xbf, 0x01, 0x0a, 0x0d, 0x42, 0x72, 0x6f, 0x61, + 0x64, 0x63, 0x61, 0x73, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x38, 0x0a, 0x07, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6d, 0x69, 0x6c, + 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x73, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x40, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x2a, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x42, 0x72, 0x6f, 0x61, + 0x64, 0x63, 0x61, 0x73, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x32, 0x0a, 0x15, 0x61, 0x63, 0x6b, 0x65, 0x64, 0x5f, 0x76, + 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x70, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x13, 0x61, 0x63, 0x6b, 0x65, 0x64, 0x56, 0x63, 0x68, 0x61, 0x6e, + 0x6e, 0x65, 0x6c, 0x42, 0x69, 0x74, 0x6d, 0x61, 0x70, 0x22, 0x7f, 0x0a, 0x0b, 0x41, 0x63, 0x6b, + 0x65, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x68, 0x61, 0x6e, + 0x6e, 0x65, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x63, 0x68, 0x61, 0x6e, + 0x6e, 0x65, 0x6c, 0x73, 0x12, 0x54, 0x0a, 0x11, 0x61, 0x63, 0x6b, 0x65, 0x64, 0x5f, 0x63, 0x68, + 0x65, 0x63, 0x6b, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x27, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, + 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x41, 0x63, 0x6b, 0x65, 0x64, 0x43, 0x68, + 0x65, 0x63, 0x6b, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x10, 0x61, 0x63, 0x6b, 0x65, 0x64, 0x43, + 0x68, 0x65, 0x63, 0x6b, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x22, 0xc8, 0x01, 0x0a, 0x0f, 0x41, + 0x63, 0x6b, 0x65, 0x64, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x3d, + 0x0a, 0x0a, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x49, 0x44, 0x52, 0x09, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x64, 0x12, 0x59, 0x0a, + 0x19, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x5f, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, - 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xfa, 0x01, 0x0a, 0x11, 0x42, 0x72, - 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x50, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x36, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, - 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, - 0x61, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x75, - 0x6c, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, - 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x62, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x5f, 0x69, - 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x62, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, - 0x73, 0x74, 0x49, 0x64, 0x1a, 0x70, 0x0a, 0x0c, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x4a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x50, - 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x9f, 0x01, 0x0a, 0x13, 0x42, 0x72, 0x6f, 0x61, 0x64, - 0x63, 0x61, 0x73, 0x74, 0x41, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x25, - 0x0a, 0x0c, 0x62, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0b, 0x62, 0x72, 0x6f, 0x61, 0x64, 0x63, - 0x61, 0x73, 0x74, 0x49, 0x64, 0x12, 0x1e, 0x0a, 0x08, 0x76, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, - 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x08, 0x76, 0x63, 0x68, - 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x41, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x49, - 0x6d, 0x6d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, - 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x16, 0x0a, 0x14, 0x42, 0x72, 0x6f, 0x61, - 0x64, 0x63, 0x61, 0x73, 0x74, 0x41, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0xe9, 0x01, 0x0a, 0x1d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x57, 0x41, 0x4c, 0x42, 0x61, - 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x46, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x57, 0x41, 0x4c, 0x42, - 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x43, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x43, 0x0a, 0x05, 0x6e, 0x6f, - 0x64, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x6d, 0x69, 0x6c, 0x76, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x44, + 0x52, 0x16, 0x6c, 0x61, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, + 0x5f, 0x74, 0x69, 0x63, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x74, 0x69, 0x6d, + 0x65, 0x54, 0x69, 0x63, 0x6b, 0x22, 0x4c, 0x0a, 0x10, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, + 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x38, 0x0a, 0x07, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6d, 0x69, 0x6c, + 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x73, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x22, 0xfa, 0x01, 0x0a, 0x11, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, + 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x07, 0x72, 0x65, 0x73, + 0x75, 0x6c, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x6d, 0x69, 0x6c, + 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, + 0x69, 0x6e, 0x67, 0x2e, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x52, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x62, + 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x0b, 0x62, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x49, 0x64, 0x1a, 0x70, + 0x0a, 0x0c, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, + 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, + 0x12, 0x4a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x34, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, + 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, + 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, + 0x22, 0x9d, 0x01, 0x0a, 0x13, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x41, 0x63, + 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x25, 0x0a, 0x0c, 0x62, 0x72, 0x6f, 0x61, + 0x64, 0x63, 0x61, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, + 0x18, 0x01, 0x52, 0x0b, 0x62, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x49, 0x64, 0x12, + 0x1e, 0x0a, 0x08, 0x76, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x08, 0x76, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, + 0x3f, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x25, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x49, 0x6d, 0x6d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x22, 0x16, 0x0a, 0x14, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x41, 0x63, 0x6b, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x78, 0x0a, 0x23, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x51, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x52, 0x65, 0x70, + 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x0d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x22, 0x26, 0x0a, 0x24, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x70, 0x6c, + 0x69, 0x63, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xe9, 0x01, 0x0a, 0x1d, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x57, 0x41, 0x4c, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x50, + 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x46, 0x0a, 0x06, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x6d, + 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, + 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x57, 0x41, 0x4c, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, + 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x06, 0x63, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x12, 0x43, 0x0a, 0x05, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x57, 0x41, 0x4c, + 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x4e, 0x6f, 0x64, + 0x65, 0x73, 0x52, 0x05, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x12, 0x3b, 0x0a, 0x0b, 0x75, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x4d, 0x61, 0x73, 0x6b, 0x22, 0x41, 0x0a, 0x16, 0x57, 0x41, 0x4c, 0x42, 0x61, 0x6c, + 0x61, 0x6e, 0x63, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x12, 0x27, 0x0a, 0x0f, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x72, 0x65, 0x62, 0x61, 0x6c, 0x61, + 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x61, 0x6c, 0x6c, 0x6f, 0x77, + 0x52, 0x65, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x22, 0x6b, 0x0a, 0x15, 0x57, 0x41, 0x4c, + 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x4e, 0x6f, 0x64, + 0x65, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x66, 0x72, 0x65, 0x65, 0x7a, 0x65, 0x5f, 0x6e, 0x6f, 0x64, + 0x65, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x03, 0x52, 0x0d, 0x66, 0x72, 0x65, + 0x65, 0x7a, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x64, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x64, 0x65, + 0x66, 0x72, 0x65, 0x65, 0x7a, 0x65, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x73, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x03, 0x52, 0x0f, 0x64, 0x65, 0x66, 0x72, 0x65, 0x65, 0x7a, 0x65, 0x4e, + 0x6f, 0x64, 0x65, 0x49, 0x64, 0x73, 0x22, 0x90, 0x01, 0x0a, 0x1e, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x57, 0x41, 0x4c, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, + 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x06, 0x63, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x57, 0x41, 0x4c, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x50, 0x6f, 0x6c, - 0x69, 0x63, 0x79, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x52, 0x05, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x12, - 0x3b, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, - 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x61, 0x73, 0x6b, 0x22, 0x41, 0x0a, 0x16, - 0x57, 0x41, 0x4c, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, - 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x27, 0x0a, 0x0f, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, - 0x72, 0x65, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x0e, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x22, - 0x6b, 0x0a, 0x15, 0x57, 0x41, 0x4c, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x50, 0x6f, 0x6c, - 0x69, 0x63, 0x79, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x66, 0x72, 0x65, 0x65, - 0x7a, 0x65, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x03, 0x52, 0x0d, 0x66, 0x72, 0x65, 0x65, 0x7a, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x64, 0x73, - 0x12, 0x2a, 0x0a, 0x11, 0x64, 0x65, 0x66, 0x72, 0x65, 0x65, 0x7a, 0x65, 0x5f, 0x6e, 0x6f, 0x64, - 0x65, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x03, 0x52, 0x0f, 0x64, 0x65, 0x66, - 0x72, 0x65, 0x65, 0x7a, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x64, 0x73, 0x22, 0x90, 0x01, 0x0a, - 0x1e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x57, 0x41, 0x4c, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, - 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x46, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x2e, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, - 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x57, 0x41, 0x4c, 0x42, 0x61, 0x6c, 0x61, - 0x6e, 0x63, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, - 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x26, 0x0a, 0x0f, 0x66, 0x72, 0x65, 0x65, 0x7a, - 0x65, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x03, - 0x52, 0x0d, 0x66, 0x72, 0x65, 0x65, 0x7a, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x64, 0x73, 0x22, - 0xd1, 0x01, 0x0a, 0x19, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x69, - 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x59, 0x0a, - 0x0c, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x52, 0x65, 0x70, - 0x6f, 0x72, 0x74, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x45, 0x72, 0x72, - 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0b, 0x72, 0x65, 0x70, - 0x6f, 0x72, 0x74, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x4e, 0x0a, 0x05, 0x63, 0x6c, 0x6f, 0x73, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, - 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, - 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, - 0x00, 0x52, 0x05, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x42, 0x09, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, - 0x61, 0x6e, 0x64, 0x22, 0x9a, 0x01, 0x0a, 0x1c, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x41, 0x73, - 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x40, 0x0a, 0x08, 0x70, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, - 0x50, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x70, 0x63, - 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x38, 0x0a, 0x03, 0x65, 0x72, 0x72, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x53, 0x74, 0x72, - 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x03, 0x65, 0x72, 0x72, - 0x22, 0x20, 0x0a, 0x1e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, - 0x65, 0x6e, 0x74, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x22, 0xe4, 0x01, 0x0a, 0x1a, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, - 0x74, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x69, 0x0a, 0x0f, 0x66, 0x75, 0x6c, 0x6c, 0x5f, 0x61, 0x73, 0x73, 0x69, 0x67, 0x6e, - 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3e, 0x2e, 0x6d, 0x69, 0x6c, - 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, - 0x69, 0x6e, 0x67, 0x2e, 0x46, 0x75, 0x6c, 0x6c, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, - 0x67, 0x4e, 0x6f, 0x64, 0x65, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x57, - 0x69, 0x74, 0x68, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x0e, 0x66, 0x75, - 0x6c, 0x6c, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x4f, 0x0a, 0x05, - 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x6d, 0x69, - 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, - 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, - 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x05, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x42, 0x0a, 0x0a, - 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x82, 0x02, 0x0a, 0x26, 0x46, 0x75, + 0x69, 0x63, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x12, 0x26, 0x0a, 0x0f, 0x66, 0x72, 0x65, 0x65, 0x7a, 0x65, 0x5f, 0x6e, 0x6f, 0x64, 0x65, + 0x5f, 0x69, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x03, 0x52, 0x0d, 0x66, 0x72, 0x65, 0x65, + 0x7a, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x49, 0x64, 0x73, 0x22, 0xd1, 0x01, 0x0a, 0x19, 0x41, 0x73, + 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x59, 0x0a, 0x0c, 0x72, 0x65, 0x70, 0x6f, 0x72, + 0x74, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, + 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, + 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x41, 0x73, 0x73, + 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0b, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x45, 0x72, 0x72, + 0x6f, 0x72, 0x12, 0x4e, 0x0a, 0x05, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x36, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, + 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, + 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x05, 0x63, 0x6c, 0x6f, + 0x73, 0x65, 0x42, 0x09, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x22, 0x9a, 0x01, + 0x0a, 0x1c, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, + 0x6e, 0x74, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x40, + 0x0a, 0x08, 0x70, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x24, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x43, 0x68, 0x61, 0x6e, 0x6e, + 0x65, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x70, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, + 0x12, 0x38, 0x0a, 0x03, 0x65, 0x72, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, + 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, + 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, + 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x03, 0x65, 0x72, 0x72, 0x22, 0x20, 0x0a, 0x1e, 0x43, 0x6c, + 0x6f, 0x73, 0x65, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x69, 0x73, + 0x63, 0x6f, 0x76, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xe4, 0x01, 0x0a, + 0x1a, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x69, 0x73, 0x63, 0x6f, + 0x76, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, 0x0f, 0x66, + 0x75, 0x6c, 0x6c, 0x5f, 0x61, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3e, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x46, 0x75, 0x6c, 0x6c, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x64, 0x65, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x57, 0x69, 0x74, 0x68, 0x56, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x3d, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x56, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x69, 0x72, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x12, 0x51, 0x0a, 0x0b, 0x61, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, - 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, - 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, - 0x67, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x64, 0x65, 0x41, - 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x0b, 0x61, 0x73, 0x73, 0x69, 0x67, - 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x46, 0x0a, 0x08, 0x63, 0x63, 0x68, 0x61, 0x6e, 0x6e, - 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, - 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, - 0x67, 0x2e, 0x43, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, - 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x08, 0x63, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x22, 0x4e, + 0x73, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x0e, 0x66, 0x75, 0x6c, 0x6c, 0x41, 0x73, 0x73, 0x69, + 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x4f, 0x0a, 0x05, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x43, + 0x6c, 0x6f, 0x73, 0x65, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x69, + 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, + 0x52, 0x05, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x42, 0x0a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0xe8, 0x02, 0x0a, 0x26, 0x46, 0x75, 0x6c, 0x6c, 0x53, 0x74, 0x72, 0x65, + 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x64, 0x65, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, + 0x65, 0x6e, 0x74, 0x57, 0x69, 0x74, 0x68, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x3d, + 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x23, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, + 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x50, 0x61, 0x69, 0x72, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x51, 0x0a, + 0x0b, 0x61, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x53, 0x74, 0x72, 0x65, + 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x64, 0x65, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, + 0x65, 0x6e, 0x74, 0x52, 0x0b, 0x61, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x73, + 0x12, 0x46, 0x0a, 0x08, 0x63, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x43, 0x43, 0x68, 0x61, + 0x6e, 0x6e, 0x65, 0x6c, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x08, + 0x63, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x64, 0x0a, 0x17, 0x72, 0x65, 0x70, 0x6c, + 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x6d, 0x69, 0x6c, 0x76, + 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, + 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x16, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, + 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x4e, 0x0a, 0x12, 0x43, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x38, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, @@ -4871,604 +5372,681 @@ var file_streaming_proto_rawDesc = []byte{ 0x6e, 0x65, 0x6c, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x6e, 0x66, 0x6f, - 0x52, 0x08, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x22, 0xff, 0x01, 0x0a, 0x0d, 0x44, + 0x52, 0x08, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x22, 0xfb, 0x01, 0x0a, 0x0d, 0x44, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x2a, 0x0a, 0x03, 0x61, 0x6c, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x48, 0x00, 0x52, 0x03, 0x61, 0x6c, 0x6c, 0x12, 0x30, 0x0a, 0x06, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, - 0x48, 0x00, 0x52, 0x06, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x12, 0x41, 0x0a, 0x0a, 0x73, 0x74, - 0x61, 0x72, 0x74, 0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, - 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x44, - 0x48, 0x00, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x46, 0x72, 0x6f, 0x6d, 0x12, 0x43, 0x0a, - 0x0b, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x61, 0x66, 0x74, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x49, 0x44, 0x48, 0x00, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x41, 0x66, 0x74, - 0x65, 0x72, 0x42, 0x08, 0x0a, 0x06, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x22, 0x9d, 0x02, 0x0a, - 0x0d, 0x44, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x53, - 0x0a, 0x0c, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x69, 0x63, 0x6b, 0x5f, 0x67, 0x74, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x44, 0x65, - 0x6c, 0x69, 0x76, 0x65, 0x72, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x54, 0x69, 0x6d, 0x65, 0x54, - 0x69, 0x63, 0x6b, 0x47, 0x54, 0x48, 0x00, 0x52, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, - 0x6b, 0x47, 0x74, 0x12, 0x56, 0x0a, 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x69, 0x63, 0x6b, - 0x5f, 0x67, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x6d, 0x69, 0x6c, - 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, - 0x69, 0x6e, 0x67, 0x2e, 0x44, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x46, 0x69, 0x6c, 0x74, 0x65, - 0x72, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x47, 0x54, 0x45, 0x48, 0x00, 0x52, 0x0b, - 0x74, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x47, 0x74, 0x65, 0x12, 0x55, 0x0a, 0x0c, 0x6d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x30, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x44, 0x65, 0x6c, 0x69, 0x76, - 0x65, 0x72, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, - 0x79, 0x70, 0x65, 0x48, 0x00, 0x52, 0x0b, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, - 0x70, 0x65, 0x42, 0x08, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x22, 0x36, 0x0a, 0x17, - 0x44, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x54, 0x69, 0x6d, - 0x65, 0x54, 0x69, 0x63, 0x6b, 0x47, 0x54, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x5f, - 0x74, 0x69, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x74, 0x69, 0x6d, 0x65, - 0x54, 0x69, 0x63, 0x6b, 0x22, 0x37, 0x0a, 0x18, 0x44, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x46, - 0x69, 0x6c, 0x74, 0x65, 0x72, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x47, 0x54, 0x45, - 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x69, 0x63, 0x6b, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x08, 0x74, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x22, 0x63, 0x0a, - 0x18, 0x44, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x47, 0x0a, 0x0d, 0x6d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0e, - 0x32, 0x22, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, - 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x54, 0x79, 0x70, 0x65, 0x52, 0x0c, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, - 0x65, 0x73, 0x22, 0x61, 0x0a, 0x0e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x45, - 0x72, 0x72, 0x6f, 0x72, 0x12, 0x39, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0e, 0x32, 0x25, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x53, 0x74, 0x72, 0x65, - 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, - 0x14, 0x0a, 0x05, 0x63, 0x61, 0x75, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, - 0x63, 0x61, 0x75, 0x73, 0x65, 0x22, 0xac, 0x01, 0x0a, 0x0e, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x49, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x64, - 0x75, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x6d, 0x69, 0x6c, 0x76, - 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, - 0x6e, 0x67, 0x2e, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x64, - 0x75, 0x63, 0x65, 0x12, 0x44, 0x0a, 0x05, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x43, 0x6c, 0x6f, 0x73, - 0x65, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x48, 0x00, 0x52, 0x05, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x42, 0x09, 0x0a, 0x07, 0x72, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x22, 0x59, 0x0a, 0x15, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x72, - 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x40, 0x0a, - 0x08, 0x70, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x24, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, - 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, - 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x70, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x22, - 0x70, 0x0a, 0x15, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x72, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x12, 0x38, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, - 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, - 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x22, 0x16, 0x0a, 0x14, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, - 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xfa, 0x01, 0x0a, 0x0f, 0x50, 0x72, - 0x6f, 0x64, 0x75, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x48, 0x0a, - 0x06, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, - 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, - 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, - 0x64, 0x75, 0x63, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, - 0x06, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x4a, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x64, 0x75, - 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, - 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, - 0x67, 0x2e, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x64, - 0x75, 0x63, 0x65, 0x12, 0x45, 0x0a, 0x05, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x43, 0x6c, 0x6f, 0x73, - 0x65, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x48, 0x00, 0x52, 0x05, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x42, 0x0a, 0x0a, 0x08, 0x72, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x61, 0x0a, 0x16, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x19, 0x0a, 0x08, 0x77, 0x61, 0x6c, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x07, 0x77, 0x61, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2c, 0x0a, 0x12, 0x70, - 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x69, - 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, - 0x72, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x49, 0x64, 0x22, 0xd3, 0x01, 0x0a, 0x16, 0x50, 0x72, - 0x6f, 0x64, 0x75, 0x63, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x49, 0x64, 0x12, 0x4e, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x72, 0x6f, - 0x64, 0x75, 0x63, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x48, 0x00, 0x52, 0x06, 0x72, 0x65, 0x73, - 0x75, 0x6c, 0x74, 0x12, 0x3e, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x53, 0x74, 0x72, 0x65, - 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x48, 0x00, 0x52, 0x05, 0x65, 0x72, - 0x72, 0x6f, 0x72, 0x42, 0x0a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0xdb, 0x01, 0x0a, 0x1c, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, - 0x12, 0x30, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x6d, - 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x73, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x44, 0x52, 0x02, - 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x74, 0x69, 0x6d, 0x65, 0x74, 0x69, 0x63, 0x6b, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x74, 0x69, 0x6d, 0x65, 0x74, 0x69, 0x63, 0x6b, 0x12, 0x41, - 0x0a, 0x0a, 0x74, 0x78, 0x6e, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x54, 0x78, 0x6e, 0x43, 0x6f, - 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, 0x0a, 0x74, 0x78, 0x6e, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, - 0x74, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x78, 0x74, 0x72, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x05, 0x65, 0x78, 0x74, 0x72, 0x61, 0x22, 0x17, 0x0a, - 0x15, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xa9, 0x03, 0x0a, 0x0e, 0x43, 0x6f, 0x6e, 0x73, 0x75, - 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x71, 0x0a, 0x18, 0x63, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x5f, 0x76, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x63, 0x6f, 0x6e, - 0x73, 0x75, 0x6d, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x6d, 0x69, - 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, - 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x56, 0x43, 0x68, 0x61, 0x6e, - 0x6e, 0x65, 0x6c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x48, 0x00, 0x52, 0x16, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x56, 0x63, 0x68, 0x61, - 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x12, 0x74, 0x0a, 0x19, - 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x76, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, - 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x36, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, - 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x56, - 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x17, 0x63, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x56, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, - 0x72, 0x73, 0x12, 0x5d, 0x0a, 0x0e, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x5f, 0x76, 0x63, 0x68, 0x61, - 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x6d, 0x69, 0x6c, - 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, - 0x69, 0x6e, 0x67, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x56, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, - 0x6c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x48, 0x00, 0x52, 0x0d, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x56, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, - 0x6c, 0x12, 0x44, 0x0a, 0x05, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x2c, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, - 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x43, - 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, - 0x52, 0x05, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x42, 0x09, 0x0a, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x22, 0x16, 0x0a, 0x14, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x73, 0x75, - 0x6d, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x59, 0x0a, 0x15, 0x43, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x40, 0x0a, 0x08, 0x70, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x50, - 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x70, 0x63, 0x68, - 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x22, 0x82, 0x01, 0x0a, 0x1e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x56, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x60, 0x0a, 0x10, 0x63, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x5f, 0x76, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x43, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x56, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, - 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x0f, 0x63, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x56, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x22, 0xd9, 0x01, 0x0a, 0x1d, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x56, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6f, 0x6e, - 0x73, 0x75, 0x6d, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, - 0x76, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, - 0x76, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x4c, 0x0a, 0x0e, 0x64, 0x65, 0x6c, 0x69, - 0x76, 0x65, 0x72, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x25, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x48, 0x00, 0x52, 0x06, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x12, 0x3f, 0x0a, 0x0a, 0x73, 0x74, + 0x61, 0x72, 0x74, 0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, + 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, + 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x44, 0x48, 0x00, + 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x46, 0x72, 0x6f, 0x6d, 0x12, 0x41, 0x0a, 0x0b, 0x73, + 0x74, 0x61, 0x72, 0x74, 0x5f, 0x61, 0x66, 0x74, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1e, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x44, + 0x48, 0x00, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x41, 0x66, 0x74, 0x65, 0x72, 0x42, 0x08, + 0x0a, 0x06, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x22, 0x9d, 0x02, 0x0a, 0x0d, 0x44, 0x65, 0x6c, + 0x69, 0x76, 0x65, 0x72, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x53, 0x0a, 0x0c, 0x74, 0x69, + 0x6d, 0x65, 0x5f, 0x74, 0x69, 0x63, 0x6b, 0x5f, 0x67, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x2f, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x44, 0x65, 0x6c, 0x69, 0x76, 0x65, - 0x72, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x0d, 0x64, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, - 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x4e, 0x0a, 0x0f, 0x64, 0x65, 0x6c, 0x69, 0x76, 0x65, - 0x72, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x25, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, - 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x44, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, - 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x0e, 0x64, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x46, - 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x22, 0x84, 0x01, 0x0a, 0x1f, 0x43, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x56, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, - 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x61, 0x0a, 0x10, 0x63, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x5f, 0x76, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x43, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x56, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6f, 0x6e, 0x73, - 0x75, 0x6d, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x0f, 0x63, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x56, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x22, 0x8f, 0x01, - 0x0a, 0x1e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x56, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, - 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x21, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, - 0x72, 0x49, 0x64, 0x12, 0x3e, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x53, 0x74, 0x72, 0x65, - 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x48, 0x00, 0x52, 0x05, 0x65, 0x72, - 0x72, 0x6f, 0x72, 0x42, 0x0a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x3f, 0x0a, 0x1c, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x56, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, - 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x1f, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x49, 0x64, - 0x22, 0x40, 0x0a, 0x1d, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x56, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, - 0x6c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x5f, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, - 0x49, 0x64, 0x22, 0xa2, 0x04, 0x0a, 0x0f, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x48, 0x0a, 0x06, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, + 0x72, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x47, + 0x54, 0x48, 0x00, 0x52, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x47, 0x74, 0x12, + 0x56, 0x0a, 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x69, 0x63, 0x6b, 0x5f, 0x67, 0x74, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x06, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x12, 0x49, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x2d, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x75, - 0x6d, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x48, 0x00, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x12, 0x61, 0x0a, 0x0f, 0x63, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x76, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x43, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x56, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6f, 0x6e, 0x73, - 0x75, 0x6d, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x0e, - 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x56, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x64, - 0x0a, 0x10, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x76, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, - 0x6c, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, - 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, - 0x67, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x56, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, - 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x48, 0x00, 0x52, 0x0f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x56, 0x63, 0x68, 0x61, 0x6e, - 0x6e, 0x65, 0x6c, 0x73, 0x12, 0x5e, 0x0a, 0x0e, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x5f, 0x76, 0x63, - 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x6d, - 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, - 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x56, 0x43, 0x68, 0x61, 0x6e, - 0x6e, 0x65, 0x6c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x0d, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x56, 0x63, 0x68, 0x61, - 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x45, 0x0a, 0x05, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x18, 0x06, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x43, 0x6c, 0x6f, - 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x48, 0x00, 0x52, 0x05, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x42, 0x0a, 0x0a, 0x08, 0x72, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x61, 0x0a, 0x16, 0x43, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x19, 0x0a, 0x08, 0x77, 0x61, 0x6c, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x07, 0x77, 0x61, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2c, 0x0a, 0x12, - 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, - 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, - 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x49, 0x64, 0x22, 0x7b, 0x0a, 0x15, 0x43, 0x6f, - 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x5f, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, - 0x65, 0x72, 0x49, 0x64, 0x12, 0x41, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x49, 0x6d, - 0x6d, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x07, - 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x17, 0x0a, 0x15, 0x43, 0x6c, 0x6f, 0x73, 0x65, - 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x65, 0x0a, 0x21, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x64, - 0x65, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x40, 0x0a, 0x08, 0x70, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, - 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, - 0x2e, 0x50, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x70, - 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x22, 0x24, 0x0a, 0x22, 0x53, 0x74, 0x72, 0x65, 0x61, - 0x6d, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x41, - 0x73, 0x73, 0x69, 0x67, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x65, 0x0a, - 0x21, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x61, - 0x6e, 0x61, 0x67, 0x65, 0x72, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x44, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x54, 0x69, 0x6d, + 0x65, 0x54, 0x69, 0x63, 0x6b, 0x47, 0x54, 0x45, 0x48, 0x00, 0x52, 0x0b, 0x74, 0x69, 0x6d, 0x65, + 0x54, 0x69, 0x63, 0x6b, 0x47, 0x74, 0x65, 0x12, 0x55, 0x0a, 0x0c, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, + 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, + 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x44, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x46, 0x69, + 0x6c, 0x74, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x48, + 0x00, 0x52, 0x0b, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x42, 0x08, + 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x22, 0x36, 0x0a, 0x17, 0x44, 0x65, 0x6c, 0x69, + 0x76, 0x65, 0x72, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, + 0x6b, 0x47, 0x54, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x69, 0x63, 0x6b, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x74, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, + 0x22, 0x37, 0x0a, 0x18, 0x44, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x46, 0x69, 0x6c, 0x74, 0x65, + 0x72, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x47, 0x54, 0x45, 0x12, 0x1b, 0x0a, 0x09, + 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x69, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x08, 0x74, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x22, 0x63, 0x0a, 0x18, 0x44, 0x65, 0x6c, + 0x69, 0x76, 0x65, 0x72, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x47, 0x0a, 0x0d, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x22, 0x2e, 0x6d, + 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x73, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, + 0x52, 0x0c, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x22, 0x61, + 0x0a, 0x0e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x45, 0x72, 0x72, 0x6f, 0x72, + 0x12, 0x39, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x25, + 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, + 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, + 0x67, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, + 0x61, 0x75, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x63, 0x61, 0x75, 0x73, + 0x65, 0x22, 0x61, 0x0a, 0x1d, 0x47, 0x65, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, + 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x40, 0x0a, 0x08, 0x70, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x70, 0x63, 0x68, 0x61, - 0x6e, 0x6e, 0x65, 0x6c, 0x22, 0x24, 0x0a, 0x22, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, - 0x67, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x52, 0x65, 0x6d, 0x6f, - 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2a, 0x0a, 0x28, 0x53, 0x74, - 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x61, 0x6e, 0x61, 0x67, - 0x65, 0x72, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x5b, 0x0a, 0x14, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, - 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x43, - 0x0a, 0x04, 0x77, 0x61, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x6d, - 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, - 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x4e, - 0x6f, 0x64, 0x65, 0x57, 0x41, 0x4c, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x04, 0x77, - 0x61, 0x6c, 0x73, 0x22, 0xe8, 0x01, 0x0a, 0x17, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, - 0x67, 0x4e, 0x6f, 0x64, 0x65, 0x57, 0x41, 0x4c, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, - 0x38, 0x0a, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, + 0x6e, 0x6e, 0x65, 0x6c, 0x22, 0x6a, 0x0a, 0x1e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x69, + 0x63, 0x61, 0x74, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x48, 0x0a, 0x0a, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x70, + 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x6d, 0x69, 0x6c, + 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, + 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x70, + 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x0a, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x70, 0x6f, 0x69, 0x6e, 0x74, + 0x22, 0xac, 0x01, 0x0a, 0x0e, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x49, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x72, + 0x6f, 0x64, 0x75, 0x63, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x12, 0x44, + 0x0a, 0x05, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, - 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x49, - 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x43, 0x0a, 0x02, 0x72, 0x77, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x53, - 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x57, 0x57, 0x41, - 0x4c, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x48, 0x00, 0x52, 0x02, 0x72, 0x77, 0x12, 0x43, - 0x0a, 0x02, 0x72, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x6d, 0x69, 0x6c, + 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x50, 0x72, 0x6f, 0x64, + 0x75, 0x63, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x05, 0x63, + 0x6c, 0x6f, 0x73, 0x65, 0x42, 0x09, 0x0a, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, + 0x59, 0x0a, 0x15, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, + 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x40, 0x0a, 0x08, 0x70, 0x63, 0x68, 0x61, + 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, - 0x69, 0x6e, 0x67, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x64, - 0x65, 0x52, 0x4f, 0x57, 0x41, 0x4c, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x48, 0x00, 0x52, - 0x02, 0x72, 0x6f, 0x42, 0x09, 0x0a, 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x22, 0x6f, - 0x0a, 0x19, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x64, 0x65, 0x52, - 0x57, 0x57, 0x41, 0x4c, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x24, 0x0a, 0x0e, 0x6d, - 0x76, 0x63, 0x63, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x69, 0x63, 0x6b, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x0c, 0x6d, 0x76, 0x63, 0x63, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, - 0x6b, 0x12, 0x2c, 0x0a, 0x12, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x5f, 0x74, 0x69, - 0x6d, 0x65, 0x5f, 0x74, 0x69, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x10, 0x72, - 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x22, - 0x1b, 0x0a, 0x19, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x64, 0x65, - 0x52, 0x4f, 0x57, 0x41, 0x4c, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x22, 0x73, 0x0a, 0x29, - 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x61, 0x6e, - 0x61, 0x67, 0x65, 0x72, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x07, 0x6d, 0x65, 0x74, - 0x72, 0x69, 0x63, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x6d, 0x69, 0x6c, - 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, - 0x69, 0x6e, 0x67, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x64, - 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, - 0x73, 0x22, 0xf4, 0x01, 0x0a, 0x0c, 0x56, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x4d, 0x65, - 0x74, 0x61, 0x12, 0x1a, 0x0a, 0x08, 0x76, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x76, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x3b, - 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x25, 0x2e, - 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, - 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x56, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x53, - 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x59, 0x0a, 0x0f, 0x63, - 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x43, 0x6f, - 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x4f, 0x66, 0x56, 0x43, - 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x0e, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x30, 0x0a, 0x14, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x70, - 0x6f, 0x69, 0x6e, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x69, 0x63, 0x6b, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x12, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x70, 0x6f, 0x69, 0x6e, 0x74, - 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x22, 0xde, 0x01, 0x0a, 0x18, 0x43, 0x6f, 0x6c, - 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x4f, 0x66, 0x56, 0x43, 0x68, - 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, 0x6f, - 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x4f, 0x0a, 0x0a, 0x70, 0x61, - 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, - 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, - 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, - 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x4f, 0x66, 0x56, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, - 0x0a, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x4c, 0x0a, 0x07, 0x73, - 0x63, 0x68, 0x65, 0x6d, 0x61, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x6d, - 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, - 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x4f, 0x66, 0x56, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, - 0x52, 0x07, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x73, 0x22, 0xd0, 0x01, 0x0a, 0x1a, 0x43, 0x6f, - 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x4f, 0x66, - 0x56, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x3d, 0x0a, 0x06, 0x73, 0x63, 0x68, 0x65, - 0x6d, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, - 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x43, - 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, - 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x30, 0x0a, 0x14, 0x63, 0x68, 0x65, 0x63, 0x6b, - 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x69, 0x63, 0x6b, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x12, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x70, 0x6f, 0x69, 0x6e, - 0x74, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x12, 0x41, 0x0a, 0x05, 0x73, 0x74, 0x61, - 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2b, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, + 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x6e, 0x66, 0x6f, + 0x52, 0x08, 0x70, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x22, 0x70, 0x0a, 0x15, 0x50, 0x72, + 0x6f, 0x64, 0x75, 0x63, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x49, 0x64, 0x12, 0x38, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x16, 0x0a, 0x14, + 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x22, 0xfa, 0x01, 0x0a, 0x0f, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x48, 0x0a, 0x06, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, - 0x67, 0x2e, 0x56, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, - 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, 0x3c, 0x0a, 0x17, - 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x4f, 0x66, 0x56, - 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x61, 0x72, 0x74, 0x69, - 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x70, - 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0xfe, 0x02, 0x0a, 0x15, 0x53, - 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, - 0x4d, 0x65, 0x74, 0x61, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, 0x6f, 0x6c, - 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x61, 0x72, - 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, - 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x09, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x76, - 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x76, - 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x44, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2e, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, - 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, - 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x41, 0x0a, - 0x04, 0x73, 0x74, 0x61, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x6d, 0x69, - 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, - 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x41, 0x73, 0x73, 0x69, - 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x52, 0x04, 0x73, 0x74, 0x61, 0x74, - 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x73, 0x74, 0x6f, 0x72, 0x61, - 0x67, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x30, 0x0a, 0x14, 0x63, 0x68, 0x65, - 0x63, 0x6b, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x69, 0x63, - 0x6b, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x12, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x70, 0x6f, - 0x69, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x22, 0xab, 0x03, 0x0a, 0x15, - 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, - 0x74, 0x53, 0x74, 0x61, 0x74, 0x12, 0x26, 0x0a, 0x0f, 0x6d, 0x61, 0x78, 0x5f, 0x62, 0x69, 0x6e, - 0x61, 0x72, 0x79, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, - 0x6d, 0x61, 0x78, 0x42, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x23, 0x0a, - 0x0d, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, 0x72, 0x6f, 0x77, 0x73, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x52, 0x6f, - 0x77, 0x73, 0x12, 0x30, 0x0a, 0x14, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, 0x62, - 0x69, 0x6e, 0x61, 0x72, 0x79, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x12, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x42, 0x69, 0x6e, 0x61, 0x72, 0x79, - 0x53, 0x69, 0x7a, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, - 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, - 0x36, 0x0a, 0x17, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, - 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x15, 0x6c, 0x61, 0x73, 0x74, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x54, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x25, 0x0a, 0x0e, 0x62, 0x69, 0x6e, 0x6c, 0x6f, - 0x67, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x0d, 0x62, 0x69, 0x6e, 0x6c, 0x6f, 0x67, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x37, - 0x0a, 0x18, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, - 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x69, 0x63, 0x6b, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x15, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x54, - 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x12, 0x35, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, - 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1f, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x53, 0x65, 0x67, 0x6d, 0x65, - 0x6e, 0x74, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x19, - 0x0a, 0x08, 0x6d, 0x61, 0x78, 0x5f, 0x72, 0x6f, 0x77, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x07, 0x6d, 0x61, 0x78, 0x52, 0x6f, 0x77, 0x73, 0x22, 0x94, 0x01, 0x0a, 0x0d, 0x57, 0x41, - 0x4c, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x3f, 0x0a, 0x0a, 0x6d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x20, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, - 0x44, 0x52, 0x09, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, - 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x69, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x08, 0x74, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x12, 0x25, 0x0a, 0x0e, 0x72, 0x65, 0x63, - 0x6f, 0x76, 0x65, 0x72, 0x79, 0x5f, 0x6d, 0x61, 0x67, 0x69, 0x63, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x0d, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x4d, 0x61, 0x67, 0x69, 0x63, - 0x2a, 0x51, 0x0a, 0x12, 0x50, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x41, 0x63, 0x63, 0x65, - 0x73, 0x73, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x1d, 0x0a, 0x19, 0x50, 0x43, 0x48, 0x41, 0x4e, 0x4e, - 0x45, 0x4c, 0x5f, 0x41, 0x43, 0x43, 0x45, 0x53, 0x53, 0x5f, 0x52, 0x45, 0x41, 0x44, 0x57, 0x52, - 0x49, 0x54, 0x45, 0x10, 0x00, 0x12, 0x1c, 0x0a, 0x18, 0x50, 0x43, 0x48, 0x41, 0x4e, 0x4e, 0x45, - 0x4c, 0x5f, 0x41, 0x43, 0x43, 0x45, 0x53, 0x53, 0x5f, 0x52, 0x45, 0x41, 0x44, 0x4f, 0x4e, 0x4c, - 0x59, 0x10, 0x01, 0x2a, 0xc5, 0x01, 0x0a, 0x11, 0x50, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, - 0x4d, 0x65, 0x74, 0x61, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1f, 0x0a, 0x1b, 0x50, 0x43, 0x48, - 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x5f, 0x4d, 0x45, 0x54, 0x41, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, - 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x25, 0x0a, 0x21, 0x50, 0x43, - 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x5f, 0x4d, 0x45, 0x54, 0x41, 0x5f, 0x53, 0x54, 0x41, 0x54, - 0x45, 0x5f, 0x55, 0x4e, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x4c, 0x49, 0x5a, 0x45, 0x44, 0x10, - 0x01, 0x12, 0x21, 0x0a, 0x1d, 0x50, 0x43, 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x5f, 0x4d, 0x45, - 0x54, 0x41, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x41, 0x53, 0x53, 0x49, 0x47, 0x4e, 0x49, - 0x4e, 0x47, 0x10, 0x02, 0x12, 0x20, 0x0a, 0x1c, 0x50, 0x43, 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, - 0x5f, 0x4d, 0x45, 0x54, 0x41, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x41, 0x53, 0x53, 0x49, - 0x47, 0x4e, 0x45, 0x44, 0x10, 0x03, 0x12, 0x23, 0x0a, 0x1f, 0x50, 0x43, 0x48, 0x41, 0x4e, 0x4e, - 0x45, 0x4c, 0x5f, 0x4d, 0x45, 0x54, 0x41, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x55, 0x4e, - 0x41, 0x56, 0x41, 0x49, 0x4c, 0x41, 0x42, 0x4c, 0x45, 0x10, 0x04, 0x2a, 0x9a, 0x01, 0x0a, 0x12, - 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x53, 0x74, 0x61, - 0x74, 0x65, 0x12, 0x20, 0x0a, 0x1c, 0x42, 0x52, 0x4f, 0x41, 0x44, 0x43, 0x41, 0x53, 0x54, 0x5f, - 0x54, 0x41, 0x53, 0x4b, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, - 0x57, 0x4e, 0x10, 0x00, 0x12, 0x20, 0x0a, 0x1c, 0x42, 0x52, 0x4f, 0x41, 0x44, 0x43, 0x41, 0x53, - 0x54, 0x5f, 0x54, 0x41, 0x53, 0x4b, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x50, 0x45, 0x4e, - 0x44, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x1d, 0x0a, 0x19, 0x42, 0x52, 0x4f, 0x41, 0x44, 0x43, - 0x41, 0x53, 0x54, 0x5f, 0x54, 0x41, 0x53, 0x4b, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x44, - 0x4f, 0x4e, 0x45, 0x10, 0x02, 0x12, 0x21, 0x0a, 0x1d, 0x42, 0x52, 0x4f, 0x41, 0x44, 0x43, 0x41, - 0x53, 0x54, 0x5f, 0x54, 0x41, 0x53, 0x4b, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x57, 0x41, - 0x49, 0x54, 0x5f, 0x41, 0x43, 0x4b, 0x10, 0x03, 0x2a, 0x82, 0x04, 0x0a, 0x0d, 0x53, 0x74, 0x72, - 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x15, 0x0a, 0x11, 0x53, 0x54, - 0x52, 0x45, 0x41, 0x4d, 0x49, 0x4e, 0x47, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x4f, 0x4b, 0x10, - 0x00, 0x12, 0x24, 0x0a, 0x20, 0x53, 0x54, 0x52, 0x45, 0x41, 0x4d, 0x49, 0x4e, 0x47, 0x5f, 0x43, - 0x4f, 0x44, 0x45, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, - 0x45, 0x58, 0x49, 0x53, 0x54, 0x10, 0x01, 0x12, 0x21, 0x0a, 0x1d, 0x53, 0x54, 0x52, 0x45, 0x41, - 0x4d, 0x49, 0x4e, 0x47, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x4e, 0x45, - 0x4c, 0x5f, 0x46, 0x45, 0x4e, 0x43, 0x45, 0x44, 0x10, 0x02, 0x12, 0x1e, 0x0a, 0x1a, 0x53, 0x54, - 0x52, 0x45, 0x41, 0x4d, 0x49, 0x4e, 0x47, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x4f, 0x4e, 0x5f, - 0x53, 0x48, 0x55, 0x54, 0x44, 0x4f, 0x57, 0x4e, 0x10, 0x03, 0x12, 0x26, 0x0a, 0x22, 0x53, 0x54, - 0x52, 0x45, 0x41, 0x4d, 0x49, 0x4e, 0x47, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x49, 0x4e, 0x56, - 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x5f, 0x53, 0x45, 0x51, - 0x10, 0x04, 0x12, 0x29, 0x0a, 0x25, 0x53, 0x54, 0x52, 0x45, 0x41, 0x4d, 0x49, 0x4e, 0x47, 0x5f, - 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x55, 0x4e, 0x4d, 0x41, 0x54, 0x43, 0x48, 0x45, 0x44, 0x5f, 0x43, - 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x5f, 0x54, 0x45, 0x52, 0x4d, 0x10, 0x05, 0x12, 0x24, 0x0a, - 0x20, 0x53, 0x54, 0x52, 0x45, 0x41, 0x4d, 0x49, 0x4e, 0x47, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, - 0x49, 0x47, 0x4e, 0x4f, 0x52, 0x45, 0x44, 0x5f, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f, - 0x4e, 0x10, 0x06, 0x12, 0x18, 0x0a, 0x14, 0x53, 0x54, 0x52, 0x45, 0x41, 0x4d, 0x49, 0x4e, 0x47, - 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x49, 0x4e, 0x4e, 0x45, 0x52, 0x10, 0x07, 0x12, 0x23, 0x0a, - 0x1f, 0x53, 0x54, 0x52, 0x45, 0x41, 0x4d, 0x49, 0x4e, 0x47, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, - 0x49, 0x4e, 0x56, 0x41, 0x49, 0x4c, 0x44, 0x5f, 0x41, 0x52, 0x47, 0x55, 0x4d, 0x45, 0x4e, 0x54, - 0x10, 0x08, 0x12, 0x26, 0x0a, 0x22, 0x53, 0x54, 0x52, 0x45, 0x41, 0x4d, 0x49, 0x4e, 0x47, 0x5f, - 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, - 0x5f, 0x45, 0x58, 0x50, 0x49, 0x52, 0x45, 0x44, 0x10, 0x09, 0x12, 0x2c, 0x0a, 0x28, 0x53, 0x54, - 0x52, 0x45, 0x41, 0x4d, 0x49, 0x4e, 0x47, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x49, 0x4e, 0x56, - 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, - 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x10, 0x0a, 0x12, 0x20, 0x0a, 0x1c, 0x53, 0x54, 0x52, 0x45, - 0x41, 0x4d, 0x49, 0x4e, 0x47, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x55, 0x4e, 0x52, 0x45, 0x43, - 0x4f, 0x56, 0x45, 0x52, 0x41, 0x42, 0x4c, 0x45, 0x10, 0x0b, 0x12, 0x24, 0x0a, 0x20, 0x53, 0x54, - 0x52, 0x45, 0x41, 0x4d, 0x49, 0x4e, 0x47, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x52, 0x45, 0x53, - 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x41, 0x43, 0x51, 0x55, 0x49, 0x52, 0x45, 0x44, 0x10, 0x0c, - 0x12, 0x1b, 0x0a, 0x16, 0x53, 0x54, 0x52, 0x45, 0x41, 0x4d, 0x49, 0x4e, 0x47, 0x5f, 0x43, 0x4f, - 0x44, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0xe7, 0x07, 0x2a, 0x62, 0x0a, - 0x0d, 0x56, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1a, - 0x0a, 0x16, 0x56, 0x43, 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, - 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, 0x56, 0x43, - 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x4e, 0x4f, 0x52, - 0x4d, 0x41, 0x4c, 0x10, 0x01, 0x12, 0x1a, 0x0a, 0x16, 0x56, 0x43, 0x48, 0x41, 0x4e, 0x4e, 0x45, - 0x4c, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x44, 0x52, 0x4f, 0x50, 0x50, 0x45, 0x44, 0x10, - 0x02, 0x2a, 0x7d, 0x0a, 0x13, 0x56, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x53, 0x63, 0x68, - 0x65, 0x6d, 0x61, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x21, 0x0a, 0x1d, 0x56, 0x43, 0x48, 0x41, - 0x4e, 0x4e, 0x45, 0x4c, 0x5f, 0x53, 0x43, 0x48, 0x45, 0x4d, 0x41, 0x5f, 0x53, 0x54, 0x41, 0x54, - 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x20, 0x0a, 0x1c, 0x56, - 0x43, 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x5f, 0x53, 0x43, 0x48, 0x45, 0x4d, 0x41, 0x5f, 0x53, - 0x54, 0x41, 0x54, 0x45, 0x5f, 0x4e, 0x4f, 0x52, 0x4d, 0x41, 0x4c, 0x10, 0x01, 0x12, 0x21, 0x0a, - 0x1d, 0x56, 0x43, 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x5f, 0x53, 0x43, 0x48, 0x45, 0x4d, 0x41, - 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x44, 0x52, 0x4f, 0x50, 0x50, 0x45, 0x44, 0x10, 0x02, - 0x2a, 0x8a, 0x01, 0x0a, 0x16, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x41, 0x73, 0x73, 0x69, - 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x24, 0x0a, 0x20, 0x53, - 0x45, 0x47, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x41, 0x53, 0x53, 0x49, 0x47, 0x4e, 0x4d, 0x45, 0x4e, - 0x54, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, - 0x00, 0x12, 0x24, 0x0a, 0x20, 0x53, 0x45, 0x47, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x41, 0x53, 0x53, - 0x49, 0x47, 0x4e, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x47, 0x52, - 0x4f, 0x57, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x24, 0x0a, 0x20, 0x53, 0x45, 0x47, 0x4d, 0x45, - 0x4e, 0x54, 0x5f, 0x41, 0x53, 0x53, 0x49, 0x47, 0x4e, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x53, 0x54, - 0x41, 0x54, 0x45, 0x5f, 0x46, 0x4c, 0x55, 0x53, 0x48, 0x45, 0x44, 0x10, 0x02, 0x32, 0x89, 0x01, - 0x0a, 0x19, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x64, 0x65, 0x53, - 0x74, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x6c, 0x0a, 0x12, 0x47, - 0x65, 0x74, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, - 0x73, 0x12, 0x2e, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6d, 0x70, 0x6f, - 0x6e, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x24, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, - 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x73, 0x22, 0x00, 0x32, 0xe8, 0x01, 0x0a, 0x1e, 0x53, 0x74, - 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x42, 0x72, 0x6f, 0x61, - 0x64, 0x63, 0x61, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x62, 0x0a, 0x09, - 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x12, 0x28, 0x2e, 0x6d, 0x69, 0x6c, 0x76, - 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, - 0x6e, 0x67, 0x2e, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x42, 0x72, 0x6f, - 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, - 0x12, 0x62, 0x0a, 0x03, 0x41, 0x63, 0x6b, 0x12, 0x2b, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, - 0x2e, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x41, 0x63, 0x6b, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x42, 0x72, - 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x41, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x00, 0x32, 0xb1, 0x02, 0x0a, 0x1f, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, - 0x6e, 0x67, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, - 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x89, 0x01, 0x0a, 0x16, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x57, 0x41, 0x4c, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x50, 0x6f, 0x6c, - 0x69, 0x63, 0x79, 0x12, 0x35, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x57, 0x41, 0x4c, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x50, 0x6f, 0x6c, - 0x69, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x36, 0x2e, 0x6d, 0x69, 0x6c, - 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, - 0x69, 0x6e, 0x67, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x57, 0x41, 0x4c, 0x42, 0x61, 0x6c, - 0x61, 0x6e, 0x63, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x00, 0x12, 0x81, 0x01, 0x0a, 0x12, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, - 0x65, 0x6e, 0x74, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x12, 0x31, 0x2e, 0x6d, 0x69, - 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, - 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x44, - 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x32, - 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, - 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, - 0x6e, 0x74, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x32, 0xe1, 0x01, 0x0a, 0x1b, 0x53, 0x74, 0x72, - 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x64, 0x65, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, - 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x60, 0x0a, 0x07, 0x50, 0x72, 0x6f, 0x64, - 0x75, 0x63, 0x65, 0x12, 0x26, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, + 0x67, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x06, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x12, 0x4a, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x72, 0x6f, - 0x64, 0x75, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x6d, 0x69, - 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, - 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x12, 0x60, 0x0a, 0x07, 0x43, 0x6f, - 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x12, 0x26, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x43, - 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, + 0x64, 0x75, 0x63, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x12, 0x45, + 0x0a, 0x05, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, - 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x32, 0xbe, 0x03, 0x0a, - 0x1b, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x61, - 0x6e, 0x61, 0x67, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x81, 0x01, 0x0a, - 0x06, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x12, 0x39, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, + 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x50, 0x72, 0x6f, 0x64, + 0x75, 0x63, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x05, + 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x42, 0x0a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x65, 0x0a, 0x16, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x64, 0x75, + 0x63, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x08, 0x77, + 0x61, 0x6c, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, + 0x01, 0x52, 0x07, 0x77, 0x61, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2c, 0x0a, 0x12, 0x70, 0x72, + 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x69, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, + 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x49, 0x64, 0x22, 0xd3, 0x01, 0x0a, 0x16, 0x50, 0x72, 0x6f, + 0x64, 0x75, 0x63, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x49, 0x64, 0x12, 0x4e, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x72, 0x6f, 0x64, + 0x75, 0x63, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x48, 0x00, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, + 0x6c, 0x74, 0x12, 0x3e, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x26, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, + 0x6d, 0x69, 0x6e, 0x67, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x48, 0x00, 0x52, 0x05, 0x65, 0x72, 0x72, + 0x6f, 0x72, 0x42, 0x0a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xd9, + 0x01, 0x0a, 0x1c, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, + 0x2e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6d, 0x69, + 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x44, 0x52, 0x02, 0x69, 0x64, 0x12, + 0x1a, 0x0a, 0x08, 0x74, 0x69, 0x6d, 0x65, 0x74, 0x69, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x08, 0x74, 0x69, 0x6d, 0x65, 0x74, 0x69, 0x63, 0x6b, 0x12, 0x41, 0x0a, 0x0a, 0x74, + 0x78, 0x6e, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x21, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x54, 0x78, 0x6e, 0x43, 0x6f, 0x6e, 0x74, 0x65, + 0x78, 0x74, 0x52, 0x0a, 0x74, 0x78, 0x6e, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x2a, + 0x0a, 0x05, 0x65, 0x78, 0x74, 0x72, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x41, 0x6e, 0x79, 0x52, 0x05, 0x65, 0x78, 0x74, 0x72, 0x61, 0x22, 0x17, 0x0a, 0x15, 0x43, 0x6c, + 0x6f, 0x73, 0x65, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0xa9, 0x03, 0x0a, 0x0e, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x71, 0x0a, 0x18, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x5f, 0x76, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, + 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, + 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, + 0x67, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x56, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, + 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, + 0x00, 0x52, 0x16, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x56, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, + 0x6c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x12, 0x74, 0x0a, 0x19, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x5f, 0x76, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x63, 0x6f, 0x6e, + 0x73, 0x75, 0x6d, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x6d, + 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, + 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x56, 0x43, 0x68, 0x61, + 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x17, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x56, 0x63, + 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x73, 0x12, + 0x5d, 0x0a, 0x0e, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x5f, 0x76, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, + 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, - 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x61, - 0x6e, 0x61, 0x67, 0x65, 0x72, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x3a, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x53, 0x74, 0x72, 0x65, - 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, - 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, - 0x12, 0x81, 0x01, 0x0a, 0x06, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x12, 0x39, 0x2e, 0x6d, 0x69, + 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x56, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6f, + 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, + 0x0d, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x56, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x44, + 0x0a, 0x05, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, + 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, + 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x73, + 0x75, 0x6d, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x05, 0x63, + 0x6c, 0x6f, 0x73, 0x65, 0x42, 0x09, 0x0a, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, + 0x16, 0x0a, 0x14, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x59, 0x0a, 0x15, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x40, 0x0a, 0x08, 0x70, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x43, 0x68, 0x61, + 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x70, 0x63, 0x68, 0x61, 0x6e, 0x6e, + 0x65, 0x6c, 0x22, 0x82, 0x01, 0x0a, 0x1e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x56, 0x43, 0x68, + 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x60, 0x0a, 0x10, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, + 0x76, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x35, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, + 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x56, + 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x0f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x56, 0x63, + 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x22, 0xd9, 0x01, 0x0a, 0x1d, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x56, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, + 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x76, 0x63, 0x68, + 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x76, 0x63, 0x68, + 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x4c, 0x0a, 0x0e, 0x64, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, + 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, + 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, + 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x44, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x50, 0x6f, + 0x6c, 0x69, 0x63, 0x79, 0x52, 0x0d, 0x64, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x50, 0x6f, 0x6c, + 0x69, 0x63, 0x79, 0x12, 0x4e, 0x0a, 0x0f, 0x64, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x5f, 0x66, + 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x6d, + 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, + 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x44, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x46, 0x69, 0x6c, + 0x74, 0x65, 0x72, 0x52, 0x0e, 0x64, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x46, 0x69, 0x6c, 0x74, + 0x65, 0x72, 0x73, 0x22, 0x84, 0x01, 0x0a, 0x1f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x56, 0x43, + 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x61, 0x0a, 0x10, 0x63, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x5f, 0x76, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x36, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x56, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, + 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x0f, 0x63, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x56, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x22, 0x8f, 0x01, 0x0a, 0x1e, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x56, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6f, 0x6e, + 0x73, 0x75, 0x6d, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x21, 0x0a, + 0x0b, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x03, 0x48, 0x00, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x49, 0x64, + 0x12, 0x3e, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x26, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, + 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, + 0x6e, 0x67, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x48, 0x00, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, + 0x42, 0x0a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3f, 0x0a, 0x1c, + 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x56, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6f, 0x6e, + 0x73, 0x75, 0x6d, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, + 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x49, 0x64, 0x22, 0x40, 0x0a, + 0x1d, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x56, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6f, + 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, + 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x49, 0x64, 0x22, + 0xa2, 0x04, 0x0a, 0x0f, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x48, 0x0a, 0x06, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x06, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x49, 0x0a, + 0x07, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, + 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, + 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, + 0x07, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x12, 0x61, 0x0a, 0x0f, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x5f, 0x76, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x36, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x56, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, + 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x0e, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x56, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x64, 0x0a, 0x10, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x76, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x56, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6f, 0x6e, + 0x73, 0x75, 0x6d, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, + 0x52, 0x0f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x56, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, + 0x73, 0x12, 0x5e, 0x0a, 0x0e, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x5f, 0x76, 0x63, 0x68, 0x61, 0x6e, + 0x6e, 0x65, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x6d, 0x69, 0x6c, 0x76, + 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, + 0x6e, 0x67, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x56, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, + 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x48, 0x00, 0x52, 0x0d, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x56, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, + 0x6c, 0x12, 0x45, 0x0a, 0x05, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x2d, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x43, + 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, + 0x00, 0x52, 0x05, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x42, 0x0a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x65, 0x0a, 0x16, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, + 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, + 0x0a, 0x08, 0x77, 0x61, 0x6c, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x42, 0x02, 0x18, 0x01, 0x52, 0x07, 0x77, 0x61, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2c, 0x0a, + 0x12, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x63, 0x6f, 0x6e, 0x73, 0x75, + 0x6d, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x49, 0x64, 0x22, 0x79, 0x0a, 0x15, 0x43, + 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, + 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x73, 0x75, + 0x6d, 0x65, 0x72, 0x49, 0x64, 0x12, 0x3f, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x49, 0x6d, 0x6d, + 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x07, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x17, 0x0a, 0x15, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x43, + 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x65, 0x0a, 0x21, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x64, 0x65, + 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x40, 0x0a, 0x08, 0x70, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, + 0x50, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x70, 0x63, + 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x22, 0x24, 0x0a, 0x22, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, + 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x41, 0x73, + 0x73, 0x69, 0x67, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x65, 0x0a, 0x21, + 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x61, 0x6e, + 0x61, 0x67, 0x65, 0x72, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x40, 0x0a, 0x08, 0x70, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x43, 0x68, + 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x70, 0x63, 0x68, 0x61, 0x6e, + 0x6e, 0x65, 0x6c, 0x22, 0x24, 0x0a, 0x22, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, + 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x52, 0x65, 0x6d, 0x6f, 0x76, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2a, 0x0a, 0x28, 0x53, 0x74, 0x72, + 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, + 0x72, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x5b, 0x0a, 0x14, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, + 0x6e, 0x67, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x43, 0x0a, + 0x04, 0x77, 0x61, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x4e, 0x6f, - 0x64, 0x65, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3a, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, + 0x64, 0x65, 0x57, 0x41, 0x4c, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x04, 0x77, 0x61, + 0x6c, 0x73, 0x22, 0xe8, 0x01, 0x0a, 0x17, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, + 0x4e, 0x6f, 0x64, 0x65, 0x57, 0x41, 0x4c, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x38, + 0x0a, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x6d, + 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, + 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x6e, + 0x66, 0x6f, 0x52, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x43, 0x0a, 0x02, 0x72, 0x77, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x53, 0x74, + 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x57, 0x57, 0x41, 0x4c, + 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x48, 0x00, 0x52, 0x02, 0x72, 0x77, 0x12, 0x43, 0x0a, + 0x02, 0x72, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x6d, 0x69, 0x6c, 0x76, + 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, + 0x6e, 0x67, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x64, 0x65, + 0x52, 0x4f, 0x57, 0x41, 0x4c, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x48, 0x00, 0x52, 0x02, + 0x72, 0x6f, 0x42, 0x09, 0x0a, 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x22, 0x6f, 0x0a, + 0x19, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x57, + 0x57, 0x41, 0x4c, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x24, 0x0a, 0x0e, 0x6d, 0x76, + 0x63, 0x63, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x69, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x0c, 0x6d, 0x76, 0x63, 0x63, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, + 0x12, 0x2c, 0x0a, 0x12, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x5f, 0x74, 0x69, 0x6d, + 0x65, 0x5f, 0x74, 0x69, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x10, 0x72, 0x65, + 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x22, 0x1b, + 0x0a, 0x19, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x64, 0x65, 0x52, + 0x4f, 0x57, 0x41, 0x4c, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x22, 0x73, 0x0a, 0x29, 0x53, + 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x61, 0x6e, 0x61, + 0x67, 0x65, 0x72, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x07, 0x6d, 0x65, 0x74, 0x72, + 0x69, 0x63, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x6d, 0x69, 0x6c, 0x76, + 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, + 0x6e, 0x67, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x64, 0x65, + 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, + 0x22, 0xf4, 0x01, 0x0a, 0x0c, 0x56, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x4d, 0x65, 0x74, + 0x61, 0x12, 0x1a, 0x0a, 0x08, 0x76, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x76, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x3b, 0x0a, + 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x25, 0x2e, 0x6d, + 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, + 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x56, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x53, 0x74, + 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x59, 0x0a, 0x0f, 0x63, 0x6f, + 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x43, 0x6f, 0x6c, + 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x4f, 0x66, 0x56, 0x43, 0x68, + 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x0e, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x30, 0x0a, 0x14, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x70, 0x6f, + 0x69, 0x6e, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x69, 0x63, 0x6b, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x12, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x54, + 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x22, 0xde, 0x01, 0x0a, 0x18, 0x43, 0x6f, 0x6c, 0x6c, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x4f, 0x66, 0x56, 0x43, 0x68, 0x61, + 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, 0x6f, 0x6c, + 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x4f, 0x0a, 0x0a, 0x70, 0x61, 0x72, + 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, + 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, + 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x49, 0x6e, 0x66, 0x6f, 0x4f, 0x66, 0x56, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x0a, + 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x4c, 0x0a, 0x07, 0x73, 0x63, + 0x68, 0x65, 0x6d, 0x61, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x6d, 0x69, + 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, + 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, + 0x63, 0x68, 0x65, 0x6d, 0x61, 0x4f, 0x66, 0x56, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, + 0x07, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x73, 0x22, 0xd0, 0x01, 0x0a, 0x1a, 0x43, 0x6f, 0x6c, + 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x4f, 0x66, 0x56, + 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x3d, 0x0a, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, + 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x43, 0x6f, + 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x06, + 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x30, 0x0a, 0x14, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x70, + 0x6f, 0x69, 0x6e, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x69, 0x63, 0x6b, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x12, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x70, 0x6f, 0x69, 0x6e, 0x74, + 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x12, 0x41, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, + 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2b, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, + 0x2e, 0x56, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x53, + 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, 0x3c, 0x0a, 0x17, 0x50, + 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x4f, 0x66, 0x56, 0x43, + 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, + 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x70, 0x61, + 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0xfe, 0x02, 0x0a, 0x15, 0x53, 0x65, + 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x4d, + 0x65, 0x74, 0x61, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x61, 0x72, 0x74, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, + 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x73, + 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x09, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x76, 0x63, + 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x76, 0x63, + 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x44, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2e, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x53, + 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, + 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x41, 0x0a, 0x04, + 0x73, 0x74, 0x61, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x6d, 0x69, 0x6c, + 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, + 0x69, 0x6e, 0x67, 0x2e, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x41, 0x73, 0x73, 0x69, 0x67, + 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x52, 0x04, 0x73, 0x74, 0x61, 0x74, 0x12, + 0x27, 0x0a, 0x0f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, + 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x30, 0x0a, 0x14, 0x63, 0x68, 0x65, 0x63, + 0x6b, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x69, 0x63, 0x6b, + 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x12, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x70, 0x6f, 0x69, + 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x22, 0xab, 0x03, 0x0a, 0x15, 0x53, + 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, + 0x53, 0x74, 0x61, 0x74, 0x12, 0x26, 0x0a, 0x0f, 0x6d, 0x61, 0x78, 0x5f, 0x62, 0x69, 0x6e, 0x61, + 0x72, 0x79, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x6d, + 0x61, 0x78, 0x42, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x23, 0x0a, 0x0d, + 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, 0x72, 0x6f, 0x77, 0x73, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x0c, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x52, 0x6f, 0x77, + 0x73, 0x12, 0x30, 0x0a, 0x14, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, 0x62, 0x69, + 0x6e, 0x61, 0x72, 0x79, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x12, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x42, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x53, + 0x69, 0x7a, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x36, + 0x0a, 0x17, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, + 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x15, 0x6c, 0x61, 0x73, 0x74, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x54, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x25, 0x0a, 0x0e, 0x62, 0x69, 0x6e, 0x6c, 0x6f, 0x67, + 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, + 0x62, 0x69, 0x6e, 0x6c, 0x6f, 0x67, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x37, 0x0a, + 0x18, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x5f, + 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x69, 0x63, 0x6b, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x15, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x54, 0x69, + 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x12, 0x35, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, + 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1f, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, + 0x74, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x19, 0x0a, + 0x08, 0x6d, 0x61, 0x78, 0x5f, 0x72, 0x6f, 0x77, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x07, 0x6d, 0x61, 0x78, 0x52, 0x6f, 0x77, 0x73, 0x22, 0xc7, 0x02, 0x0a, 0x0d, 0x57, 0x41, 0x4c, + 0x43, 0x68, 0x65, 0x63, 0x6b, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x3d, 0x0a, 0x0a, 0x6d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, + 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, + 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x44, 0x52, 0x09, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x69, 0x6d, + 0x65, 0x5f, 0x74, 0x69, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x74, 0x69, + 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x12, 0x25, 0x0a, 0x0e, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, + 0x72, 0x79, 0x5f, 0x6d, 0x61, 0x67, 0x69, 0x63, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, + 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x4d, 0x61, 0x67, 0x69, 0x63, 0x12, 0x56, 0x0a, + 0x10, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x52, 0x65, + 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0f, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x5b, 0x0a, 0x14, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, + 0x74, 0x65, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, + 0x61, 0x74, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x13, 0x72, + 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x70, 0x6f, 0x69, + 0x6e, 0x74, 0x22, 0xca, 0x01, 0x0a, 0x1a, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, + 0x61, 0x12, 0x64, 0x0a, 0x17, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x63, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, + 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x16, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x46, 0x0a, 0x0c, 0x61, 0x63, 0x6b, 0x65, 0x64, + 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, + 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, + 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x41, 0x63, 0x6b, 0x65, 0x64, 0x52, 0x65, 0x73, 0x75, + 0x6c, 0x74, 0x52, 0x0b, 0x61, 0x63, 0x6b, 0x65, 0x64, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, + 0xa3, 0x02, 0x0a, 0x15, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x50, 0x43, 0x68, + 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x2e, 0x0a, 0x13, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x6e, 0x61, 0x6d, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x68, + 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2e, 0x0a, 0x13, 0x74, 0x61, 0x72, + 0x67, 0x65, 0x74, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x6e, 0x61, 0x6d, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x68, + 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x49, 0x0a, 0x0e, 0x74, 0x61, 0x72, + 0x67, 0x65, 0x74, 0x5f, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x22, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x43, 0x6c, + 0x75, 0x73, 0x74, 0x65, 0x72, 0x52, 0x0d, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x6c, 0x75, + 0x73, 0x74, 0x65, 0x72, 0x12, 0x5f, 0x0a, 0x16, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x69, + 0x7a, 0x65, 0x64, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x69, + 0x63, 0x61, 0x74, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x15, + 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x43, 0x68, 0x65, 0x63, 0x6b, + 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x2a, 0x51, 0x0a, 0x12, 0x50, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, + 0x6c, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x1d, 0x0a, 0x19, 0x50, + 0x43, 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x5f, 0x41, 0x43, 0x43, 0x45, 0x53, 0x53, 0x5f, 0x52, + 0x45, 0x41, 0x44, 0x57, 0x52, 0x49, 0x54, 0x45, 0x10, 0x00, 0x12, 0x1c, 0x0a, 0x18, 0x50, 0x43, + 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x5f, 0x41, 0x43, 0x43, 0x45, 0x53, 0x53, 0x5f, 0x52, 0x45, + 0x41, 0x44, 0x4f, 0x4e, 0x4c, 0x59, 0x10, 0x01, 0x2a, 0xc5, 0x01, 0x0a, 0x11, 0x50, 0x43, 0x68, + 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x4d, 0x65, 0x74, 0x61, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1f, + 0x0a, 0x1b, 0x50, 0x43, 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x5f, 0x4d, 0x45, 0x54, 0x41, 0x5f, + 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, + 0x25, 0x0a, 0x21, 0x50, 0x43, 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x5f, 0x4d, 0x45, 0x54, 0x41, + 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x4c, + 0x49, 0x5a, 0x45, 0x44, 0x10, 0x01, 0x12, 0x21, 0x0a, 0x1d, 0x50, 0x43, 0x48, 0x41, 0x4e, 0x4e, + 0x45, 0x4c, 0x5f, 0x4d, 0x45, 0x54, 0x41, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x41, 0x53, + 0x53, 0x49, 0x47, 0x4e, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x12, 0x20, 0x0a, 0x1c, 0x50, 0x43, 0x48, + 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x5f, 0x4d, 0x45, 0x54, 0x41, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, + 0x5f, 0x41, 0x53, 0x53, 0x49, 0x47, 0x4e, 0x45, 0x44, 0x10, 0x03, 0x12, 0x23, 0x0a, 0x1f, 0x50, + 0x43, 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x5f, 0x4d, 0x45, 0x54, 0x41, 0x5f, 0x53, 0x54, 0x41, + 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x41, 0x56, 0x41, 0x49, 0x4c, 0x41, 0x42, 0x4c, 0x45, 0x10, 0x04, + 0x2a, 0x9a, 0x01, 0x0a, 0x12, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x54, 0x61, + 0x73, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x20, 0x0a, 0x1c, 0x42, 0x52, 0x4f, 0x41, 0x44, + 0x43, 0x41, 0x53, 0x54, 0x5f, 0x54, 0x41, 0x53, 0x4b, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, + 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x20, 0x0a, 0x1c, 0x42, 0x52, 0x4f, + 0x41, 0x44, 0x43, 0x41, 0x53, 0x54, 0x5f, 0x54, 0x41, 0x53, 0x4b, 0x5f, 0x53, 0x54, 0x41, 0x54, + 0x45, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x1d, 0x0a, 0x19, 0x42, + 0x52, 0x4f, 0x41, 0x44, 0x43, 0x41, 0x53, 0x54, 0x5f, 0x54, 0x41, 0x53, 0x4b, 0x5f, 0x53, 0x54, + 0x41, 0x54, 0x45, 0x5f, 0x44, 0x4f, 0x4e, 0x45, 0x10, 0x02, 0x12, 0x21, 0x0a, 0x1d, 0x42, 0x52, + 0x4f, 0x41, 0x44, 0x43, 0x41, 0x53, 0x54, 0x5f, 0x54, 0x41, 0x53, 0x4b, 0x5f, 0x53, 0x54, 0x41, + 0x54, 0x45, 0x5f, 0x57, 0x41, 0x49, 0x54, 0x5f, 0x41, 0x43, 0x4b, 0x10, 0x03, 0x2a, 0xaa, 0x04, + 0x0a, 0x0d, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x64, 0x65, 0x12, + 0x15, 0x0a, 0x11, 0x53, 0x54, 0x52, 0x45, 0x41, 0x4d, 0x49, 0x4e, 0x47, 0x5f, 0x43, 0x4f, 0x44, + 0x45, 0x5f, 0x4f, 0x4b, 0x10, 0x00, 0x12, 0x24, 0x0a, 0x20, 0x53, 0x54, 0x52, 0x45, 0x41, 0x4d, + 0x49, 0x4e, 0x47, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, + 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x45, 0x58, 0x49, 0x53, 0x54, 0x10, 0x01, 0x12, 0x21, 0x0a, 0x1d, + 0x53, 0x54, 0x52, 0x45, 0x41, 0x4d, 0x49, 0x4e, 0x47, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x43, + 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x5f, 0x46, 0x45, 0x4e, 0x43, 0x45, 0x44, 0x10, 0x02, 0x12, + 0x1e, 0x0a, 0x1a, 0x53, 0x54, 0x52, 0x45, 0x41, 0x4d, 0x49, 0x4e, 0x47, 0x5f, 0x43, 0x4f, 0x44, + 0x45, 0x5f, 0x4f, 0x4e, 0x5f, 0x53, 0x48, 0x55, 0x54, 0x44, 0x4f, 0x57, 0x4e, 0x10, 0x03, 0x12, + 0x26, 0x0a, 0x22, 0x53, 0x54, 0x52, 0x45, 0x41, 0x4d, 0x49, 0x4e, 0x47, 0x5f, 0x43, 0x4f, 0x44, + 0x45, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, + 0x54, 0x5f, 0x53, 0x45, 0x51, 0x10, 0x04, 0x12, 0x29, 0x0a, 0x25, 0x53, 0x54, 0x52, 0x45, 0x41, + 0x4d, 0x49, 0x4e, 0x47, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x55, 0x4e, 0x4d, 0x41, 0x54, 0x43, + 0x48, 0x45, 0x44, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x5f, 0x54, 0x45, 0x52, 0x4d, + 0x10, 0x05, 0x12, 0x24, 0x0a, 0x20, 0x53, 0x54, 0x52, 0x45, 0x41, 0x4d, 0x49, 0x4e, 0x47, 0x5f, + 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x49, 0x47, 0x4e, 0x4f, 0x52, 0x45, 0x44, 0x5f, 0x4f, 0x50, 0x45, + 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x06, 0x12, 0x18, 0x0a, 0x14, 0x53, 0x54, 0x52, 0x45, + 0x41, 0x4d, 0x49, 0x4e, 0x47, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x49, 0x4e, 0x4e, 0x45, 0x52, + 0x10, 0x07, 0x12, 0x23, 0x0a, 0x1f, 0x53, 0x54, 0x52, 0x45, 0x41, 0x4d, 0x49, 0x4e, 0x47, 0x5f, + 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x49, 0x4c, 0x44, 0x5f, 0x41, 0x52, 0x47, + 0x55, 0x4d, 0x45, 0x4e, 0x54, 0x10, 0x08, 0x12, 0x26, 0x0a, 0x22, 0x53, 0x54, 0x52, 0x45, 0x41, + 0x4d, 0x49, 0x4e, 0x47, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x41, + 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x45, 0x58, 0x50, 0x49, 0x52, 0x45, 0x44, 0x10, 0x09, 0x12, + 0x2c, 0x0a, 0x28, 0x53, 0x54, 0x52, 0x45, 0x41, 0x4d, 0x49, 0x4e, 0x47, 0x5f, 0x43, 0x4f, 0x44, + 0x45, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x5f, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x41, + 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x10, 0x0a, 0x12, 0x20, 0x0a, + 0x1c, 0x53, 0x54, 0x52, 0x45, 0x41, 0x4d, 0x49, 0x4e, 0x47, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, + 0x55, 0x4e, 0x52, 0x45, 0x43, 0x4f, 0x56, 0x45, 0x52, 0x41, 0x42, 0x4c, 0x45, 0x10, 0x0b, 0x12, + 0x24, 0x0a, 0x20, 0x53, 0x54, 0x52, 0x45, 0x41, 0x4d, 0x49, 0x4e, 0x47, 0x5f, 0x43, 0x4f, 0x44, + 0x45, 0x5f, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x41, 0x43, 0x51, 0x55, 0x49, + 0x52, 0x45, 0x44, 0x10, 0x0c, 0x12, 0x26, 0x0a, 0x22, 0x53, 0x54, 0x52, 0x45, 0x41, 0x4d, 0x49, + 0x4e, 0x47, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x52, 0x45, 0x50, 0x4c, 0x49, 0x43, 0x41, 0x54, + 0x45, 0x5f, 0x56, 0x49, 0x4f, 0x4c, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x0d, 0x12, 0x1b, 0x0a, + 0x16, 0x53, 0x54, 0x52, 0x45, 0x41, 0x4d, 0x49, 0x4e, 0x47, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, + 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0xe7, 0x07, 0x2a, 0x62, 0x0a, 0x0d, 0x56, 0x43, + 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1a, 0x0a, 0x16, 0x56, + 0x43, 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x55, 0x4e, + 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, 0x56, 0x43, 0x48, 0x41, 0x4e, + 0x4e, 0x45, 0x4c, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x4e, 0x4f, 0x52, 0x4d, 0x41, 0x4c, + 0x10, 0x01, 0x12, 0x1a, 0x0a, 0x16, 0x56, 0x43, 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x5f, 0x53, + 0x54, 0x41, 0x54, 0x45, 0x5f, 0x44, 0x52, 0x4f, 0x50, 0x50, 0x45, 0x44, 0x10, 0x02, 0x2a, 0x7d, + 0x0a, 0x13, 0x56, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, + 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x21, 0x0a, 0x1d, 0x56, 0x43, 0x48, 0x41, 0x4e, 0x4e, 0x45, + 0x4c, 0x5f, 0x53, 0x43, 0x48, 0x45, 0x4d, 0x41, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x55, + 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x20, 0x0a, 0x1c, 0x56, 0x43, 0x48, 0x41, + 0x4e, 0x4e, 0x45, 0x4c, 0x5f, 0x53, 0x43, 0x48, 0x45, 0x4d, 0x41, 0x5f, 0x53, 0x54, 0x41, 0x54, + 0x45, 0x5f, 0x4e, 0x4f, 0x52, 0x4d, 0x41, 0x4c, 0x10, 0x01, 0x12, 0x21, 0x0a, 0x1d, 0x56, 0x43, + 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x5f, 0x53, 0x43, 0x48, 0x45, 0x4d, 0x41, 0x5f, 0x53, 0x54, + 0x41, 0x54, 0x45, 0x5f, 0x44, 0x52, 0x4f, 0x50, 0x50, 0x45, 0x44, 0x10, 0x02, 0x2a, 0x8a, 0x01, + 0x0a, 0x16, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, + 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x24, 0x0a, 0x20, 0x53, 0x45, 0x47, 0x4d, + 0x45, 0x4e, 0x54, 0x5f, 0x41, 0x53, 0x53, 0x49, 0x47, 0x4e, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x53, + 0x54, 0x41, 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x24, + 0x0a, 0x20, 0x53, 0x45, 0x47, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x41, 0x53, 0x53, 0x49, 0x47, 0x4e, + 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x47, 0x52, 0x4f, 0x57, 0x49, + 0x4e, 0x47, 0x10, 0x01, 0x12, 0x24, 0x0a, 0x20, 0x53, 0x45, 0x47, 0x4d, 0x45, 0x4e, 0x54, 0x5f, + 0x41, 0x53, 0x53, 0x49, 0x47, 0x4e, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, + 0x5f, 0x46, 0x4c, 0x55, 0x53, 0x48, 0x45, 0x44, 0x10, 0x02, 0x32, 0x89, 0x01, 0x0a, 0x19, 0x53, + 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x64, 0x65, 0x53, 0x74, 0x61, 0x74, + 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x6c, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x43, + 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x73, 0x12, 0x2e, + 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x69, + 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, + 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, + 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x69, + 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x53, 0x74, + 0x61, 0x74, 0x65, 0x73, 0x22, 0x00, 0x32, 0xe8, 0x01, 0x0a, 0x1e, 0x53, 0x74, 0x72, 0x65, 0x61, + 0x6d, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, + 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x62, 0x0a, 0x09, 0x42, 0x72, 0x6f, + 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x12, 0x28, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, - 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x61, 0x6e, - 0x61, 0x67, 0x65, 0x72, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x00, 0x12, 0x96, 0x01, 0x0a, 0x0d, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, - 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x40, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, + 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x29, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, + 0x61, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x62, 0x0a, + 0x03, 0x41, 0x63, 0x6b, 0x12, 0x2b, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x42, 0x72, + 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x41, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x2c, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x42, 0x72, 0x6f, 0x61, 0x64, + 0x63, 0x61, 0x73, 0x74, 0x41, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x00, 0x32, 0xcf, 0x03, 0x0a, 0x1f, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x43, + 0x6f, 0x6f, 0x72, 0x64, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x9b, 0x01, 0x0a, 0x1c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3b, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, - 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x61, 0x6e, - 0x61, 0x67, 0x65, 0x72, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x41, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, - 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, - 0x67, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x64, 0x65, 0x4d, - 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x53, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x36, 0x5a, - 0x34, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6d, 0x69, 0x6c, 0x76, - 0x75, 0x73, 0x2d, 0x69, 0x6f, 0x2f, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2f, 0x70, 0x6b, 0x67, - 0x2f, 0x76, 0x32, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, - 0x69, 0x6e, 0x67, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x3c, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x00, 0x12, 0x89, 0x01, 0x0a, 0x16, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x57, 0x41, + 0x4c, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x35, + 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, + 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x57, 0x41, + 0x4c, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x36, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x57, 0x41, 0x4c, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x50, + 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, + 0x81, 0x01, 0x0a, 0x12, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x69, + 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x12, 0x31, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, + 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, + 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x32, 0x2e, 0x6d, 0x69, 0x6c, 0x76, + 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, + 0x6e, 0x67, 0x2e, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x44, 0x69, 0x73, + 0x63, 0x6f, 0x76, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28, + 0x01, 0x30, 0x01, 0x32, 0xed, 0x02, 0x0a, 0x1b, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, + 0x67, 0x4e, 0x6f, 0x64, 0x65, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x12, 0x89, 0x01, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x69, + 0x63, 0x61, 0x74, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x35, + 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, + 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x69, + 0x63, 0x61, 0x74, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x36, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x47, + 0x65, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, + 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, + 0x60, 0x0a, 0x07, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x12, 0x26, 0x2e, 0x6d, 0x69, 0x6c, + 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, + 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x72, 0x6f, 0x64, + 0x75, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28, 0x01, 0x30, + 0x01, 0x12, 0x60, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x12, 0x26, 0x2e, 0x6d, + 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, + 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x43, 0x6f, + 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28, + 0x01, 0x30, 0x01, 0x32, 0xbe, 0x03, 0x0a, 0x1b, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, + 0x67, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x12, 0x81, 0x01, 0x0a, 0x06, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x12, 0x39, + 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, + 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, + 0x67, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x41, 0x73, 0x73, 0x69, + 0x67, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3a, 0x2e, 0x6d, 0x69, 0x6c, 0x76, + 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, + 0x6e, 0x67, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x64, 0x65, + 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x81, 0x01, 0x0a, 0x06, 0x52, 0x65, 0x6d, 0x6f, + 0x76, 0x65, 0x12, 0x39, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x53, 0x74, 0x72, 0x65, + 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, + 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3a, 0x2e, + 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, + 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, + 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x52, 0x65, 0x6d, 0x6f, 0x76, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x96, 0x01, 0x0a, 0x0d, + 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x40, 0x2e, + 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x74, 0x72, + 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, + 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x43, 0x6f, 0x6c, 0x6c, 0x65, + 0x63, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x41, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, + 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, + 0x6e, 0x67, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x43, 0x6f, 0x6c, + 0x6c, 0x65, 0x63, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x00, 0x42, 0x36, 0x5a, 0x34, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2d, 0x69, 0x6f, 0x2f, 0x6d, 0x69, 0x6c, + 0x76, 0x75, 0x73, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x76, 0x32, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -5484,7 +6062,7 @@ func file_streaming_proto_rawDescGZIP() []byte { } var file_streaming_proto_enumTypes = make([]protoimpl.EnumInfo, 7) -var file_streaming_proto_msgTypes = make([]protoimpl.MessageInfo, 70) +var file_streaming_proto_msgTypes = make([]protoimpl.MessageInfo, 78) var file_streaming_proto_goTypes = []interface{}{ (PChannelAccessMode)(0), // 0: milvus.proto.streaming.PChannelAccessMode (PChannelMetaState)(0), // 1: milvus.proto.streaming.PChannelMetaState @@ -5500,192 +6078,220 @@ var file_streaming_proto_goTypes = []interface{}{ (*StreamingVersion)(nil), // 11: milvus.proto.streaming.StreamingVersion (*VersionPair)(nil), // 12: milvus.proto.streaming.VersionPair (*BroadcastTask)(nil), // 13: milvus.proto.streaming.BroadcastTask - (*BroadcastRequest)(nil), // 14: milvus.proto.streaming.BroadcastRequest - (*BroadcastResponse)(nil), // 15: milvus.proto.streaming.BroadcastResponse - (*BroadcastAckRequest)(nil), // 16: milvus.proto.streaming.BroadcastAckRequest - (*BroadcastAckResponse)(nil), // 17: milvus.proto.streaming.BroadcastAckResponse - (*UpdateWALBalancePolicyRequest)(nil), // 18: milvus.proto.streaming.UpdateWALBalancePolicyRequest - (*WALBalancePolicyConfig)(nil), // 19: milvus.proto.streaming.WALBalancePolicyConfig - (*WALBalancePolicyNodes)(nil), // 20: milvus.proto.streaming.WALBalancePolicyNodes - (*UpdateWALBalancePolicyResponse)(nil), // 21: milvus.proto.streaming.UpdateWALBalancePolicyResponse - (*AssignmentDiscoverRequest)(nil), // 22: milvus.proto.streaming.AssignmentDiscoverRequest - (*ReportAssignmentErrorRequest)(nil), // 23: milvus.proto.streaming.ReportAssignmentErrorRequest - (*CloseAssignmentDiscoverRequest)(nil), // 24: milvus.proto.streaming.CloseAssignmentDiscoverRequest - (*AssignmentDiscoverResponse)(nil), // 25: milvus.proto.streaming.AssignmentDiscoverResponse - (*FullStreamingNodeAssignmentWithVersion)(nil), // 26: milvus.proto.streaming.FullStreamingNodeAssignmentWithVersion - (*CChannelAssignment)(nil), // 27: milvus.proto.streaming.CChannelAssignment - (*CloseAssignmentDiscoverResponse)(nil), // 28: milvus.proto.streaming.CloseAssignmentDiscoverResponse - (*StreamingNodeInfo)(nil), // 29: milvus.proto.streaming.StreamingNodeInfo - (*StreamingNodeAssignment)(nil), // 30: milvus.proto.streaming.StreamingNodeAssignment - (*DeliverPolicy)(nil), // 31: milvus.proto.streaming.DeliverPolicy - (*DeliverFilter)(nil), // 32: milvus.proto.streaming.DeliverFilter - (*DeliverFilterTimeTickGT)(nil), // 33: milvus.proto.streaming.DeliverFilterTimeTickGT - (*DeliverFilterTimeTickGTE)(nil), // 34: milvus.proto.streaming.DeliverFilterTimeTickGTE - (*DeliverFilterMessageType)(nil), // 35: milvus.proto.streaming.DeliverFilterMessageType - (*StreamingError)(nil), // 36: milvus.proto.streaming.StreamingError - (*ProduceRequest)(nil), // 37: milvus.proto.streaming.ProduceRequest - (*CreateProducerRequest)(nil), // 38: milvus.proto.streaming.CreateProducerRequest - (*ProduceMessageRequest)(nil), // 39: milvus.proto.streaming.ProduceMessageRequest - (*CloseProducerRequest)(nil), // 40: milvus.proto.streaming.CloseProducerRequest - (*ProduceResponse)(nil), // 41: milvus.proto.streaming.ProduceResponse - (*CreateProducerResponse)(nil), // 42: milvus.proto.streaming.CreateProducerResponse - (*ProduceMessageResponse)(nil), // 43: milvus.proto.streaming.ProduceMessageResponse - (*ProduceMessageResponseResult)(nil), // 44: milvus.proto.streaming.ProduceMessageResponseResult - (*CloseProducerResponse)(nil), // 45: milvus.proto.streaming.CloseProducerResponse - (*ConsumeRequest)(nil), // 46: milvus.proto.streaming.ConsumeRequest - (*CloseConsumerRequest)(nil), // 47: milvus.proto.streaming.CloseConsumerRequest - (*CreateConsumerRequest)(nil), // 48: milvus.proto.streaming.CreateConsumerRequest - (*CreateVChannelConsumersRequest)(nil), // 49: milvus.proto.streaming.CreateVChannelConsumersRequest - (*CreateVChannelConsumerRequest)(nil), // 50: milvus.proto.streaming.CreateVChannelConsumerRequest - (*CreateVChannelConsumersResponse)(nil), // 51: milvus.proto.streaming.CreateVChannelConsumersResponse - (*CreateVChannelConsumerResponse)(nil), // 52: milvus.proto.streaming.CreateVChannelConsumerResponse - (*CloseVChannelConsumerRequest)(nil), // 53: milvus.proto.streaming.CloseVChannelConsumerRequest - (*CloseVChannelConsumerResponse)(nil), // 54: milvus.proto.streaming.CloseVChannelConsumerResponse - (*ConsumeResponse)(nil), // 55: milvus.proto.streaming.ConsumeResponse - (*CreateConsumerResponse)(nil), // 56: milvus.proto.streaming.CreateConsumerResponse - (*ConsumeMessageReponse)(nil), // 57: milvus.proto.streaming.ConsumeMessageReponse - (*CloseConsumerResponse)(nil), // 58: milvus.proto.streaming.CloseConsumerResponse - (*StreamingNodeManagerAssignRequest)(nil), // 59: milvus.proto.streaming.StreamingNodeManagerAssignRequest - (*StreamingNodeManagerAssignResponse)(nil), // 60: milvus.proto.streaming.StreamingNodeManagerAssignResponse - (*StreamingNodeManagerRemoveRequest)(nil), // 61: milvus.proto.streaming.StreamingNodeManagerRemoveRequest - (*StreamingNodeManagerRemoveResponse)(nil), // 62: milvus.proto.streaming.StreamingNodeManagerRemoveResponse - (*StreamingNodeManagerCollectStatusRequest)(nil), // 63: milvus.proto.streaming.StreamingNodeManagerCollectStatusRequest - (*StreamingNodeMetrics)(nil), // 64: milvus.proto.streaming.StreamingNodeMetrics - (*StreamingNodeWALMetrics)(nil), // 65: milvus.proto.streaming.StreamingNodeWALMetrics - (*StreamingNodeRWWALMetrics)(nil), // 66: milvus.proto.streaming.StreamingNodeRWWALMetrics - (*StreamingNodeROWALMetrics)(nil), // 67: milvus.proto.streaming.StreamingNodeROWALMetrics - (*StreamingNodeManagerCollectStatusResponse)(nil), // 68: milvus.proto.streaming.StreamingNodeManagerCollectStatusResponse - (*VChannelMeta)(nil), // 69: milvus.proto.streaming.VChannelMeta - (*CollectionInfoOfVChannel)(nil), // 70: milvus.proto.streaming.CollectionInfoOfVChannel - (*CollectionSchemaOfVChannel)(nil), // 71: milvus.proto.streaming.CollectionSchemaOfVChannel - (*PartitionInfoOfVChannel)(nil), // 72: milvus.proto.streaming.PartitionInfoOfVChannel - (*SegmentAssignmentMeta)(nil), // 73: milvus.proto.streaming.SegmentAssignmentMeta - (*SegmentAssignmentStat)(nil), // 74: milvus.proto.streaming.SegmentAssignmentStat - (*WALCheckpoint)(nil), // 75: milvus.proto.streaming.WALCheckpoint - nil, // 76: milvus.proto.streaming.BroadcastResponse.ResultsEntry - (*messagespb.Message)(nil), // 77: milvus.proto.messages.Message - (*messagespb.ImmutableMessage)(nil), // 78: milvus.proto.messages.ImmutableMessage - (*fieldmaskpb.FieldMask)(nil), // 79: google.protobuf.FieldMask - (*emptypb.Empty)(nil), // 80: google.protobuf.Empty - (*messagespb.MessageID)(nil), // 81: milvus.proto.messages.MessageID - (messagespb.MessageType)(0), // 82: milvus.proto.messages.MessageType - (*messagespb.TxnContext)(nil), // 83: milvus.proto.messages.TxnContext - (*anypb.Any)(nil), // 84: google.protobuf.Any - (*schemapb.CollectionSchema)(nil), // 85: milvus.proto.schema.CollectionSchema - (datapb.SegmentLevel)(0), // 86: milvus.proto.data.SegmentLevel - (*milvuspb.GetComponentStatesRequest)(nil), // 87: milvus.proto.milvus.GetComponentStatesRequest - (*milvuspb.ComponentStates)(nil), // 88: milvus.proto.milvus.ComponentStates + (*AckedResult)(nil), // 14: milvus.proto.streaming.AckedResult + (*AckedCheckpoint)(nil), // 15: milvus.proto.streaming.AckedCheckpoint + (*BroadcastRequest)(nil), // 16: milvus.proto.streaming.BroadcastRequest + (*BroadcastResponse)(nil), // 17: milvus.proto.streaming.BroadcastResponse + (*BroadcastAckRequest)(nil), // 18: milvus.proto.streaming.BroadcastAckRequest + (*BroadcastAckResponse)(nil), // 19: milvus.proto.streaming.BroadcastAckResponse + (*UpdateReplicateConfigurationRequest)(nil), // 20: milvus.proto.streaming.UpdateReplicateConfigurationRequest + (*UpdateReplicateConfigurationResponse)(nil), // 21: milvus.proto.streaming.UpdateReplicateConfigurationResponse + (*UpdateWALBalancePolicyRequest)(nil), // 22: milvus.proto.streaming.UpdateWALBalancePolicyRequest + (*WALBalancePolicyConfig)(nil), // 23: milvus.proto.streaming.WALBalancePolicyConfig + (*WALBalancePolicyNodes)(nil), // 24: milvus.proto.streaming.WALBalancePolicyNodes + (*UpdateWALBalancePolicyResponse)(nil), // 25: milvus.proto.streaming.UpdateWALBalancePolicyResponse + (*AssignmentDiscoverRequest)(nil), // 26: milvus.proto.streaming.AssignmentDiscoverRequest + (*ReportAssignmentErrorRequest)(nil), // 27: milvus.proto.streaming.ReportAssignmentErrorRequest + (*CloseAssignmentDiscoverRequest)(nil), // 28: milvus.proto.streaming.CloseAssignmentDiscoverRequest + (*AssignmentDiscoverResponse)(nil), // 29: milvus.proto.streaming.AssignmentDiscoverResponse + (*FullStreamingNodeAssignmentWithVersion)(nil), // 30: milvus.proto.streaming.FullStreamingNodeAssignmentWithVersion + (*CChannelAssignment)(nil), // 31: milvus.proto.streaming.CChannelAssignment + (*CloseAssignmentDiscoverResponse)(nil), // 32: milvus.proto.streaming.CloseAssignmentDiscoverResponse + (*StreamingNodeInfo)(nil), // 33: milvus.proto.streaming.StreamingNodeInfo + (*StreamingNodeAssignment)(nil), // 34: milvus.proto.streaming.StreamingNodeAssignment + (*DeliverPolicy)(nil), // 35: milvus.proto.streaming.DeliverPolicy + (*DeliverFilter)(nil), // 36: milvus.proto.streaming.DeliverFilter + (*DeliverFilterTimeTickGT)(nil), // 37: milvus.proto.streaming.DeliverFilterTimeTickGT + (*DeliverFilterTimeTickGTE)(nil), // 38: milvus.proto.streaming.DeliverFilterTimeTickGTE + (*DeliverFilterMessageType)(nil), // 39: milvus.proto.streaming.DeliverFilterMessageType + (*StreamingError)(nil), // 40: milvus.proto.streaming.StreamingError + (*GetReplicateCheckpointRequest)(nil), // 41: milvus.proto.streaming.GetReplicateCheckpointRequest + (*GetReplicateCheckpointResponse)(nil), // 42: milvus.proto.streaming.GetReplicateCheckpointResponse + (*ProduceRequest)(nil), // 43: milvus.proto.streaming.ProduceRequest + (*CreateProducerRequest)(nil), // 44: milvus.proto.streaming.CreateProducerRequest + (*ProduceMessageRequest)(nil), // 45: milvus.proto.streaming.ProduceMessageRequest + (*CloseProducerRequest)(nil), // 46: milvus.proto.streaming.CloseProducerRequest + (*ProduceResponse)(nil), // 47: milvus.proto.streaming.ProduceResponse + (*CreateProducerResponse)(nil), // 48: milvus.proto.streaming.CreateProducerResponse + (*ProduceMessageResponse)(nil), // 49: milvus.proto.streaming.ProduceMessageResponse + (*ProduceMessageResponseResult)(nil), // 50: milvus.proto.streaming.ProduceMessageResponseResult + (*CloseProducerResponse)(nil), // 51: milvus.proto.streaming.CloseProducerResponse + (*ConsumeRequest)(nil), // 52: milvus.proto.streaming.ConsumeRequest + (*CloseConsumerRequest)(nil), // 53: milvus.proto.streaming.CloseConsumerRequest + (*CreateConsumerRequest)(nil), // 54: milvus.proto.streaming.CreateConsumerRequest + (*CreateVChannelConsumersRequest)(nil), // 55: milvus.proto.streaming.CreateVChannelConsumersRequest + (*CreateVChannelConsumerRequest)(nil), // 56: milvus.proto.streaming.CreateVChannelConsumerRequest + (*CreateVChannelConsumersResponse)(nil), // 57: milvus.proto.streaming.CreateVChannelConsumersResponse + (*CreateVChannelConsumerResponse)(nil), // 58: milvus.proto.streaming.CreateVChannelConsumerResponse + (*CloseVChannelConsumerRequest)(nil), // 59: milvus.proto.streaming.CloseVChannelConsumerRequest + (*CloseVChannelConsumerResponse)(nil), // 60: milvus.proto.streaming.CloseVChannelConsumerResponse + (*ConsumeResponse)(nil), // 61: milvus.proto.streaming.ConsumeResponse + (*CreateConsumerResponse)(nil), // 62: milvus.proto.streaming.CreateConsumerResponse + (*ConsumeMessageReponse)(nil), // 63: milvus.proto.streaming.ConsumeMessageReponse + (*CloseConsumerResponse)(nil), // 64: milvus.proto.streaming.CloseConsumerResponse + (*StreamingNodeManagerAssignRequest)(nil), // 65: milvus.proto.streaming.StreamingNodeManagerAssignRequest + (*StreamingNodeManagerAssignResponse)(nil), // 66: milvus.proto.streaming.StreamingNodeManagerAssignResponse + (*StreamingNodeManagerRemoveRequest)(nil), // 67: milvus.proto.streaming.StreamingNodeManagerRemoveRequest + (*StreamingNodeManagerRemoveResponse)(nil), // 68: milvus.proto.streaming.StreamingNodeManagerRemoveResponse + (*StreamingNodeManagerCollectStatusRequest)(nil), // 69: milvus.proto.streaming.StreamingNodeManagerCollectStatusRequest + (*StreamingNodeMetrics)(nil), // 70: milvus.proto.streaming.StreamingNodeMetrics + (*StreamingNodeWALMetrics)(nil), // 71: milvus.proto.streaming.StreamingNodeWALMetrics + (*StreamingNodeRWWALMetrics)(nil), // 72: milvus.proto.streaming.StreamingNodeRWWALMetrics + (*StreamingNodeROWALMetrics)(nil), // 73: milvus.proto.streaming.StreamingNodeROWALMetrics + (*StreamingNodeManagerCollectStatusResponse)(nil), // 74: milvus.proto.streaming.StreamingNodeManagerCollectStatusResponse + (*VChannelMeta)(nil), // 75: milvus.proto.streaming.VChannelMeta + (*CollectionInfoOfVChannel)(nil), // 76: milvus.proto.streaming.CollectionInfoOfVChannel + (*CollectionSchemaOfVChannel)(nil), // 77: milvus.proto.streaming.CollectionSchemaOfVChannel + (*PartitionInfoOfVChannel)(nil), // 78: milvus.proto.streaming.PartitionInfoOfVChannel + (*SegmentAssignmentMeta)(nil), // 79: milvus.proto.streaming.SegmentAssignmentMeta + (*SegmentAssignmentStat)(nil), // 80: milvus.proto.streaming.SegmentAssignmentStat + (*WALCheckpoint)(nil), // 81: milvus.proto.streaming.WALCheckpoint + (*ReplicateConfigurationMeta)(nil), // 82: milvus.proto.streaming.ReplicateConfigurationMeta + (*ReplicatePChannelMeta)(nil), // 83: milvus.proto.streaming.ReplicatePChannelMeta + nil, // 84: milvus.proto.streaming.BroadcastResponse.ResultsEntry + (*messagespb.Message)(nil), // 85: milvus.proto.messages.Message + (*commonpb.MessageID)(nil), // 86: milvus.proto.common.MessageID + (*commonpb.ImmutableMessage)(nil), // 87: milvus.proto.common.ImmutableMessage + (*commonpb.ReplicateConfiguration)(nil), // 88: milvus.proto.common.ReplicateConfiguration + (*fieldmaskpb.FieldMask)(nil), // 89: google.protobuf.FieldMask + (*emptypb.Empty)(nil), // 90: google.protobuf.Empty + (messagespb.MessageType)(0), // 91: milvus.proto.messages.MessageType + (*commonpb.ReplicateCheckpoint)(nil), // 92: milvus.proto.common.ReplicateCheckpoint + (*messagespb.TxnContext)(nil), // 93: milvus.proto.messages.TxnContext + (*anypb.Any)(nil), // 94: google.protobuf.Any + (*schemapb.CollectionSchema)(nil), // 95: milvus.proto.schema.CollectionSchema + (datapb.SegmentLevel)(0), // 96: milvus.proto.data.SegmentLevel + (*commonpb.MilvusCluster)(nil), // 97: milvus.proto.common.MilvusCluster + (*milvuspb.GetComponentStatesRequest)(nil), // 98: milvus.proto.milvus.GetComponentStatesRequest + (*milvuspb.ComponentStates)(nil), // 99: milvus.proto.milvus.ComponentStates } var file_streaming_proto_depIdxs = []int32{ - 0, // 0: milvus.proto.streaming.PChannelInfo.access_mode:type_name -> milvus.proto.streaming.PChannelAccessMode - 29, // 1: milvus.proto.streaming.PChannelAssignmentLog.node:type_name -> milvus.proto.streaming.StreamingNodeInfo - 0, // 2: milvus.proto.streaming.PChannelAssignmentLog.access_mode:type_name -> milvus.proto.streaming.PChannelAccessMode - 7, // 3: milvus.proto.streaming.PChannelMeta.channel:type_name -> milvus.proto.streaming.PChannelInfo - 29, // 4: milvus.proto.streaming.PChannelMeta.node:type_name -> milvus.proto.streaming.StreamingNodeInfo - 1, // 5: milvus.proto.streaming.PChannelMeta.state:type_name -> milvus.proto.streaming.PChannelMetaState - 8, // 6: milvus.proto.streaming.PChannelMeta.histories:type_name -> milvus.proto.streaming.PChannelAssignmentLog - 77, // 7: milvus.proto.streaming.BroadcastTask.message:type_name -> milvus.proto.messages.Message - 2, // 8: milvus.proto.streaming.BroadcastTask.state:type_name -> milvus.proto.streaming.BroadcastTaskState - 77, // 9: milvus.proto.streaming.BroadcastRequest.message:type_name -> milvus.proto.messages.Message - 76, // 10: milvus.proto.streaming.BroadcastResponse.results:type_name -> milvus.proto.streaming.BroadcastResponse.ResultsEntry - 78, // 11: milvus.proto.streaming.BroadcastAckRequest.message:type_name -> milvus.proto.messages.ImmutableMessage - 19, // 12: milvus.proto.streaming.UpdateWALBalancePolicyRequest.config:type_name -> milvus.proto.streaming.WALBalancePolicyConfig - 20, // 13: milvus.proto.streaming.UpdateWALBalancePolicyRequest.nodes:type_name -> milvus.proto.streaming.WALBalancePolicyNodes - 79, // 14: milvus.proto.streaming.UpdateWALBalancePolicyRequest.update_mask:type_name -> google.protobuf.FieldMask - 19, // 15: milvus.proto.streaming.UpdateWALBalancePolicyResponse.config:type_name -> milvus.proto.streaming.WALBalancePolicyConfig - 23, // 16: milvus.proto.streaming.AssignmentDiscoverRequest.report_error:type_name -> milvus.proto.streaming.ReportAssignmentErrorRequest - 24, // 17: milvus.proto.streaming.AssignmentDiscoverRequest.close:type_name -> milvus.proto.streaming.CloseAssignmentDiscoverRequest - 7, // 18: milvus.proto.streaming.ReportAssignmentErrorRequest.pchannel:type_name -> milvus.proto.streaming.PChannelInfo - 36, // 19: milvus.proto.streaming.ReportAssignmentErrorRequest.err:type_name -> milvus.proto.streaming.StreamingError - 26, // 20: milvus.proto.streaming.AssignmentDiscoverResponse.full_assignment:type_name -> milvus.proto.streaming.FullStreamingNodeAssignmentWithVersion - 28, // 21: milvus.proto.streaming.AssignmentDiscoverResponse.close:type_name -> milvus.proto.streaming.CloseAssignmentDiscoverResponse - 12, // 22: milvus.proto.streaming.FullStreamingNodeAssignmentWithVersion.version:type_name -> milvus.proto.streaming.VersionPair - 30, // 23: milvus.proto.streaming.FullStreamingNodeAssignmentWithVersion.assignments:type_name -> milvus.proto.streaming.StreamingNodeAssignment - 27, // 24: milvus.proto.streaming.FullStreamingNodeAssignmentWithVersion.cchannel:type_name -> milvus.proto.streaming.CChannelAssignment - 10, // 25: milvus.proto.streaming.CChannelAssignment.meta:type_name -> milvus.proto.streaming.CChannelMeta - 29, // 26: milvus.proto.streaming.StreamingNodeAssignment.node:type_name -> milvus.proto.streaming.StreamingNodeInfo - 7, // 27: milvus.proto.streaming.StreamingNodeAssignment.channels:type_name -> milvus.proto.streaming.PChannelInfo - 80, // 28: milvus.proto.streaming.DeliverPolicy.all:type_name -> google.protobuf.Empty - 80, // 29: milvus.proto.streaming.DeliverPolicy.latest:type_name -> google.protobuf.Empty - 81, // 30: milvus.proto.streaming.DeliverPolicy.start_from:type_name -> milvus.proto.messages.MessageID - 81, // 31: milvus.proto.streaming.DeliverPolicy.start_after:type_name -> milvus.proto.messages.MessageID - 33, // 32: milvus.proto.streaming.DeliverFilter.time_tick_gt:type_name -> milvus.proto.streaming.DeliverFilterTimeTickGT - 34, // 33: milvus.proto.streaming.DeliverFilter.time_tick_gte:type_name -> milvus.proto.streaming.DeliverFilterTimeTickGTE - 35, // 34: milvus.proto.streaming.DeliverFilter.message_type:type_name -> milvus.proto.streaming.DeliverFilterMessageType - 82, // 35: milvus.proto.streaming.DeliverFilterMessageType.message_types:type_name -> milvus.proto.messages.MessageType - 3, // 36: milvus.proto.streaming.StreamingError.code:type_name -> milvus.proto.streaming.StreamingCode - 39, // 37: milvus.proto.streaming.ProduceRequest.produce:type_name -> milvus.proto.streaming.ProduceMessageRequest - 40, // 38: milvus.proto.streaming.ProduceRequest.close:type_name -> milvus.proto.streaming.CloseProducerRequest - 7, // 39: milvus.proto.streaming.CreateProducerRequest.pchannel:type_name -> milvus.proto.streaming.PChannelInfo - 77, // 40: milvus.proto.streaming.ProduceMessageRequest.message:type_name -> milvus.proto.messages.Message - 42, // 41: milvus.proto.streaming.ProduceResponse.create:type_name -> milvus.proto.streaming.CreateProducerResponse - 43, // 42: milvus.proto.streaming.ProduceResponse.produce:type_name -> milvus.proto.streaming.ProduceMessageResponse - 45, // 43: milvus.proto.streaming.ProduceResponse.close:type_name -> milvus.proto.streaming.CloseProducerResponse - 44, // 44: milvus.proto.streaming.ProduceMessageResponse.result:type_name -> milvus.proto.streaming.ProduceMessageResponseResult - 36, // 45: milvus.proto.streaming.ProduceMessageResponse.error:type_name -> milvus.proto.streaming.StreamingError - 81, // 46: milvus.proto.streaming.ProduceMessageResponseResult.id:type_name -> milvus.proto.messages.MessageID - 83, // 47: milvus.proto.streaming.ProduceMessageResponseResult.txnContext:type_name -> milvus.proto.messages.TxnContext - 84, // 48: milvus.proto.streaming.ProduceMessageResponseResult.extra:type_name -> google.protobuf.Any - 50, // 49: milvus.proto.streaming.ConsumeRequest.create_vchannel_consumer:type_name -> milvus.proto.streaming.CreateVChannelConsumerRequest - 49, // 50: milvus.proto.streaming.ConsumeRequest.create_vchannel_consumers:type_name -> milvus.proto.streaming.CreateVChannelConsumersRequest - 53, // 51: milvus.proto.streaming.ConsumeRequest.close_vchannel:type_name -> milvus.proto.streaming.CloseVChannelConsumerRequest - 47, // 52: milvus.proto.streaming.ConsumeRequest.close:type_name -> milvus.proto.streaming.CloseConsumerRequest - 7, // 53: milvus.proto.streaming.CreateConsumerRequest.pchannel:type_name -> milvus.proto.streaming.PChannelInfo - 50, // 54: milvus.proto.streaming.CreateVChannelConsumersRequest.create_vchannels:type_name -> milvus.proto.streaming.CreateVChannelConsumerRequest - 31, // 55: milvus.proto.streaming.CreateVChannelConsumerRequest.deliver_policy:type_name -> milvus.proto.streaming.DeliverPolicy - 32, // 56: milvus.proto.streaming.CreateVChannelConsumerRequest.deliver_filters:type_name -> milvus.proto.streaming.DeliverFilter - 52, // 57: milvus.proto.streaming.CreateVChannelConsumersResponse.create_vchannels:type_name -> milvus.proto.streaming.CreateVChannelConsumerResponse - 36, // 58: milvus.proto.streaming.CreateVChannelConsumerResponse.error:type_name -> milvus.proto.streaming.StreamingError - 56, // 59: milvus.proto.streaming.ConsumeResponse.create:type_name -> milvus.proto.streaming.CreateConsumerResponse - 57, // 60: milvus.proto.streaming.ConsumeResponse.consume:type_name -> milvus.proto.streaming.ConsumeMessageReponse - 52, // 61: milvus.proto.streaming.ConsumeResponse.create_vchannel:type_name -> milvus.proto.streaming.CreateVChannelConsumerResponse - 51, // 62: milvus.proto.streaming.ConsumeResponse.create_vchannels:type_name -> milvus.proto.streaming.CreateVChannelConsumersResponse - 54, // 63: milvus.proto.streaming.ConsumeResponse.close_vchannel:type_name -> milvus.proto.streaming.CloseVChannelConsumerResponse - 58, // 64: milvus.proto.streaming.ConsumeResponse.close:type_name -> milvus.proto.streaming.CloseConsumerResponse - 78, // 65: milvus.proto.streaming.ConsumeMessageReponse.message:type_name -> milvus.proto.messages.ImmutableMessage - 7, // 66: milvus.proto.streaming.StreamingNodeManagerAssignRequest.pchannel:type_name -> milvus.proto.streaming.PChannelInfo - 7, // 67: milvus.proto.streaming.StreamingNodeManagerRemoveRequest.pchannel:type_name -> milvus.proto.streaming.PChannelInfo - 65, // 68: milvus.proto.streaming.StreamingNodeMetrics.wals:type_name -> milvus.proto.streaming.StreamingNodeWALMetrics - 7, // 69: milvus.proto.streaming.StreamingNodeWALMetrics.info:type_name -> milvus.proto.streaming.PChannelInfo - 66, // 70: milvus.proto.streaming.StreamingNodeWALMetrics.rw:type_name -> milvus.proto.streaming.StreamingNodeRWWALMetrics - 67, // 71: milvus.proto.streaming.StreamingNodeWALMetrics.ro:type_name -> milvus.proto.streaming.StreamingNodeROWALMetrics - 64, // 72: milvus.proto.streaming.StreamingNodeManagerCollectStatusResponse.metrics:type_name -> milvus.proto.streaming.StreamingNodeMetrics - 4, // 73: milvus.proto.streaming.VChannelMeta.state:type_name -> milvus.proto.streaming.VChannelState - 70, // 74: milvus.proto.streaming.VChannelMeta.collection_info:type_name -> milvus.proto.streaming.CollectionInfoOfVChannel - 72, // 75: milvus.proto.streaming.CollectionInfoOfVChannel.partitions:type_name -> milvus.proto.streaming.PartitionInfoOfVChannel - 71, // 76: milvus.proto.streaming.CollectionInfoOfVChannel.schemas:type_name -> milvus.proto.streaming.CollectionSchemaOfVChannel - 85, // 77: milvus.proto.streaming.CollectionSchemaOfVChannel.schema:type_name -> milvus.proto.schema.CollectionSchema - 5, // 78: milvus.proto.streaming.CollectionSchemaOfVChannel.state:type_name -> milvus.proto.streaming.VChannelSchemaState - 6, // 79: milvus.proto.streaming.SegmentAssignmentMeta.state:type_name -> milvus.proto.streaming.SegmentAssignmentState - 74, // 80: milvus.proto.streaming.SegmentAssignmentMeta.stat:type_name -> milvus.proto.streaming.SegmentAssignmentStat - 86, // 81: milvus.proto.streaming.SegmentAssignmentStat.level:type_name -> milvus.proto.data.SegmentLevel - 81, // 82: milvus.proto.streaming.WALCheckpoint.message_id:type_name -> milvus.proto.messages.MessageID - 44, // 83: milvus.proto.streaming.BroadcastResponse.ResultsEntry.value:type_name -> milvus.proto.streaming.ProduceMessageResponseResult - 87, // 84: milvus.proto.streaming.StreamingNodeStateService.GetComponentStates:input_type -> milvus.proto.milvus.GetComponentStatesRequest - 14, // 85: milvus.proto.streaming.StreamingCoordBroadcastService.Broadcast:input_type -> milvus.proto.streaming.BroadcastRequest - 16, // 86: milvus.proto.streaming.StreamingCoordBroadcastService.Ack:input_type -> milvus.proto.streaming.BroadcastAckRequest - 18, // 87: milvus.proto.streaming.StreamingCoordAssignmentService.UpdateWALBalancePolicy:input_type -> milvus.proto.streaming.UpdateWALBalancePolicyRequest - 22, // 88: milvus.proto.streaming.StreamingCoordAssignmentService.AssignmentDiscover:input_type -> milvus.proto.streaming.AssignmentDiscoverRequest - 37, // 89: milvus.proto.streaming.StreamingNodeHandlerService.Produce:input_type -> milvus.proto.streaming.ProduceRequest - 46, // 90: milvus.proto.streaming.StreamingNodeHandlerService.Consume:input_type -> milvus.proto.streaming.ConsumeRequest - 59, // 91: milvus.proto.streaming.StreamingNodeManagerService.Assign:input_type -> milvus.proto.streaming.StreamingNodeManagerAssignRequest - 61, // 92: milvus.proto.streaming.StreamingNodeManagerService.Remove:input_type -> milvus.proto.streaming.StreamingNodeManagerRemoveRequest - 63, // 93: milvus.proto.streaming.StreamingNodeManagerService.CollectStatus:input_type -> milvus.proto.streaming.StreamingNodeManagerCollectStatusRequest - 88, // 94: milvus.proto.streaming.StreamingNodeStateService.GetComponentStates:output_type -> milvus.proto.milvus.ComponentStates - 15, // 95: milvus.proto.streaming.StreamingCoordBroadcastService.Broadcast:output_type -> milvus.proto.streaming.BroadcastResponse - 17, // 96: milvus.proto.streaming.StreamingCoordBroadcastService.Ack:output_type -> milvus.proto.streaming.BroadcastAckResponse - 21, // 97: milvus.proto.streaming.StreamingCoordAssignmentService.UpdateWALBalancePolicy:output_type -> milvus.proto.streaming.UpdateWALBalancePolicyResponse - 25, // 98: milvus.proto.streaming.StreamingCoordAssignmentService.AssignmentDiscover:output_type -> milvus.proto.streaming.AssignmentDiscoverResponse - 41, // 99: milvus.proto.streaming.StreamingNodeHandlerService.Produce:output_type -> milvus.proto.streaming.ProduceResponse - 55, // 100: milvus.proto.streaming.StreamingNodeHandlerService.Consume:output_type -> milvus.proto.streaming.ConsumeResponse - 60, // 101: milvus.proto.streaming.StreamingNodeManagerService.Assign:output_type -> milvus.proto.streaming.StreamingNodeManagerAssignResponse - 62, // 102: milvus.proto.streaming.StreamingNodeManagerService.Remove:output_type -> milvus.proto.streaming.StreamingNodeManagerRemoveResponse - 68, // 103: milvus.proto.streaming.StreamingNodeManagerService.CollectStatus:output_type -> milvus.proto.streaming.StreamingNodeManagerCollectStatusResponse - 94, // [94:104] is the sub-list for method output_type - 84, // [84:94] is the sub-list for method input_type - 84, // [84:84] is the sub-list for extension type_name - 84, // [84:84] is the sub-list for extension extendee - 0, // [0:84] is the sub-list for field type_name + 0, // 0: milvus.proto.streaming.PChannelInfo.access_mode:type_name -> milvus.proto.streaming.PChannelAccessMode + 33, // 1: milvus.proto.streaming.PChannelAssignmentLog.node:type_name -> milvus.proto.streaming.StreamingNodeInfo + 0, // 2: milvus.proto.streaming.PChannelAssignmentLog.access_mode:type_name -> milvus.proto.streaming.PChannelAccessMode + 7, // 3: milvus.proto.streaming.PChannelMeta.channel:type_name -> milvus.proto.streaming.PChannelInfo + 33, // 4: milvus.proto.streaming.PChannelMeta.node:type_name -> milvus.proto.streaming.StreamingNodeInfo + 1, // 5: milvus.proto.streaming.PChannelMeta.state:type_name -> milvus.proto.streaming.PChannelMetaState + 8, // 6: milvus.proto.streaming.PChannelMeta.histories:type_name -> milvus.proto.streaming.PChannelAssignmentLog + 85, // 7: milvus.proto.streaming.BroadcastTask.message:type_name -> milvus.proto.messages.Message + 2, // 8: milvus.proto.streaming.BroadcastTask.state:type_name -> milvus.proto.streaming.BroadcastTaskState + 15, // 9: milvus.proto.streaming.AckedResult.acked_checkpoints:type_name -> milvus.proto.streaming.AckedCheckpoint + 86, // 10: milvus.proto.streaming.AckedCheckpoint.message_id:type_name -> milvus.proto.common.MessageID + 86, // 11: milvus.proto.streaming.AckedCheckpoint.last_confirmed_message_id:type_name -> milvus.proto.common.MessageID + 85, // 12: milvus.proto.streaming.BroadcastRequest.message:type_name -> milvus.proto.messages.Message + 84, // 13: milvus.proto.streaming.BroadcastResponse.results:type_name -> milvus.proto.streaming.BroadcastResponse.ResultsEntry + 87, // 14: milvus.proto.streaming.BroadcastAckRequest.message:type_name -> milvus.proto.common.ImmutableMessage + 88, // 15: milvus.proto.streaming.UpdateReplicateConfigurationRequest.configuration:type_name -> milvus.proto.common.ReplicateConfiguration + 23, // 16: milvus.proto.streaming.UpdateWALBalancePolicyRequest.config:type_name -> milvus.proto.streaming.WALBalancePolicyConfig + 24, // 17: milvus.proto.streaming.UpdateWALBalancePolicyRequest.nodes:type_name -> milvus.proto.streaming.WALBalancePolicyNodes + 89, // 18: milvus.proto.streaming.UpdateWALBalancePolicyRequest.update_mask:type_name -> google.protobuf.FieldMask + 23, // 19: milvus.proto.streaming.UpdateWALBalancePolicyResponse.config:type_name -> milvus.proto.streaming.WALBalancePolicyConfig + 27, // 20: milvus.proto.streaming.AssignmentDiscoverRequest.report_error:type_name -> milvus.proto.streaming.ReportAssignmentErrorRequest + 28, // 21: milvus.proto.streaming.AssignmentDiscoverRequest.close:type_name -> milvus.proto.streaming.CloseAssignmentDiscoverRequest + 7, // 22: milvus.proto.streaming.ReportAssignmentErrorRequest.pchannel:type_name -> milvus.proto.streaming.PChannelInfo + 40, // 23: milvus.proto.streaming.ReportAssignmentErrorRequest.err:type_name -> milvus.proto.streaming.StreamingError + 30, // 24: milvus.proto.streaming.AssignmentDiscoverResponse.full_assignment:type_name -> milvus.proto.streaming.FullStreamingNodeAssignmentWithVersion + 32, // 25: milvus.proto.streaming.AssignmentDiscoverResponse.close:type_name -> milvus.proto.streaming.CloseAssignmentDiscoverResponse + 12, // 26: milvus.proto.streaming.FullStreamingNodeAssignmentWithVersion.version:type_name -> milvus.proto.streaming.VersionPair + 34, // 27: milvus.proto.streaming.FullStreamingNodeAssignmentWithVersion.assignments:type_name -> milvus.proto.streaming.StreamingNodeAssignment + 31, // 28: milvus.proto.streaming.FullStreamingNodeAssignmentWithVersion.cchannel:type_name -> milvus.proto.streaming.CChannelAssignment + 88, // 29: milvus.proto.streaming.FullStreamingNodeAssignmentWithVersion.replicate_configuration:type_name -> milvus.proto.common.ReplicateConfiguration + 10, // 30: milvus.proto.streaming.CChannelAssignment.meta:type_name -> milvus.proto.streaming.CChannelMeta + 33, // 31: milvus.proto.streaming.StreamingNodeAssignment.node:type_name -> milvus.proto.streaming.StreamingNodeInfo + 7, // 32: milvus.proto.streaming.StreamingNodeAssignment.channels:type_name -> milvus.proto.streaming.PChannelInfo + 90, // 33: milvus.proto.streaming.DeliverPolicy.all:type_name -> google.protobuf.Empty + 90, // 34: milvus.proto.streaming.DeliverPolicy.latest:type_name -> google.protobuf.Empty + 86, // 35: milvus.proto.streaming.DeliverPolicy.start_from:type_name -> milvus.proto.common.MessageID + 86, // 36: milvus.proto.streaming.DeliverPolicy.start_after:type_name -> milvus.proto.common.MessageID + 37, // 37: milvus.proto.streaming.DeliverFilter.time_tick_gt:type_name -> milvus.proto.streaming.DeliverFilterTimeTickGT + 38, // 38: milvus.proto.streaming.DeliverFilter.time_tick_gte:type_name -> milvus.proto.streaming.DeliverFilterTimeTickGTE + 39, // 39: milvus.proto.streaming.DeliverFilter.message_type:type_name -> milvus.proto.streaming.DeliverFilterMessageType + 91, // 40: milvus.proto.streaming.DeliverFilterMessageType.message_types:type_name -> milvus.proto.messages.MessageType + 3, // 41: milvus.proto.streaming.StreamingError.code:type_name -> milvus.proto.streaming.StreamingCode + 7, // 42: milvus.proto.streaming.GetReplicateCheckpointRequest.pchannel:type_name -> milvus.proto.streaming.PChannelInfo + 92, // 43: milvus.proto.streaming.GetReplicateCheckpointResponse.checkpoint:type_name -> milvus.proto.common.ReplicateCheckpoint + 45, // 44: milvus.proto.streaming.ProduceRequest.produce:type_name -> milvus.proto.streaming.ProduceMessageRequest + 46, // 45: milvus.proto.streaming.ProduceRequest.close:type_name -> milvus.proto.streaming.CloseProducerRequest + 7, // 46: milvus.proto.streaming.CreateProducerRequest.pchannel:type_name -> milvus.proto.streaming.PChannelInfo + 85, // 47: milvus.proto.streaming.ProduceMessageRequest.message:type_name -> milvus.proto.messages.Message + 48, // 48: milvus.proto.streaming.ProduceResponse.create:type_name -> milvus.proto.streaming.CreateProducerResponse + 49, // 49: milvus.proto.streaming.ProduceResponse.produce:type_name -> milvus.proto.streaming.ProduceMessageResponse + 51, // 50: milvus.proto.streaming.ProduceResponse.close:type_name -> milvus.proto.streaming.CloseProducerResponse + 50, // 51: milvus.proto.streaming.ProduceMessageResponse.result:type_name -> milvus.proto.streaming.ProduceMessageResponseResult + 40, // 52: milvus.proto.streaming.ProduceMessageResponse.error:type_name -> milvus.proto.streaming.StreamingError + 86, // 53: milvus.proto.streaming.ProduceMessageResponseResult.id:type_name -> milvus.proto.common.MessageID + 93, // 54: milvus.proto.streaming.ProduceMessageResponseResult.txnContext:type_name -> milvus.proto.messages.TxnContext + 94, // 55: milvus.proto.streaming.ProduceMessageResponseResult.extra:type_name -> google.protobuf.Any + 56, // 56: milvus.proto.streaming.ConsumeRequest.create_vchannel_consumer:type_name -> milvus.proto.streaming.CreateVChannelConsumerRequest + 55, // 57: milvus.proto.streaming.ConsumeRequest.create_vchannel_consumers:type_name -> milvus.proto.streaming.CreateVChannelConsumersRequest + 59, // 58: milvus.proto.streaming.ConsumeRequest.close_vchannel:type_name -> milvus.proto.streaming.CloseVChannelConsumerRequest + 53, // 59: milvus.proto.streaming.ConsumeRequest.close:type_name -> milvus.proto.streaming.CloseConsumerRequest + 7, // 60: milvus.proto.streaming.CreateConsumerRequest.pchannel:type_name -> milvus.proto.streaming.PChannelInfo + 56, // 61: milvus.proto.streaming.CreateVChannelConsumersRequest.create_vchannels:type_name -> milvus.proto.streaming.CreateVChannelConsumerRequest + 35, // 62: milvus.proto.streaming.CreateVChannelConsumerRequest.deliver_policy:type_name -> milvus.proto.streaming.DeliverPolicy + 36, // 63: milvus.proto.streaming.CreateVChannelConsumerRequest.deliver_filters:type_name -> milvus.proto.streaming.DeliverFilter + 58, // 64: milvus.proto.streaming.CreateVChannelConsumersResponse.create_vchannels:type_name -> milvus.proto.streaming.CreateVChannelConsumerResponse + 40, // 65: milvus.proto.streaming.CreateVChannelConsumerResponse.error:type_name -> milvus.proto.streaming.StreamingError + 62, // 66: milvus.proto.streaming.ConsumeResponse.create:type_name -> milvus.proto.streaming.CreateConsumerResponse + 63, // 67: milvus.proto.streaming.ConsumeResponse.consume:type_name -> milvus.proto.streaming.ConsumeMessageReponse + 58, // 68: milvus.proto.streaming.ConsumeResponse.create_vchannel:type_name -> milvus.proto.streaming.CreateVChannelConsumerResponse + 57, // 69: milvus.proto.streaming.ConsumeResponse.create_vchannels:type_name -> milvus.proto.streaming.CreateVChannelConsumersResponse + 60, // 70: milvus.proto.streaming.ConsumeResponse.close_vchannel:type_name -> milvus.proto.streaming.CloseVChannelConsumerResponse + 64, // 71: milvus.proto.streaming.ConsumeResponse.close:type_name -> milvus.proto.streaming.CloseConsumerResponse + 87, // 72: milvus.proto.streaming.ConsumeMessageReponse.message:type_name -> milvus.proto.common.ImmutableMessage + 7, // 73: milvus.proto.streaming.StreamingNodeManagerAssignRequest.pchannel:type_name -> milvus.proto.streaming.PChannelInfo + 7, // 74: milvus.proto.streaming.StreamingNodeManagerRemoveRequest.pchannel:type_name -> milvus.proto.streaming.PChannelInfo + 71, // 75: milvus.proto.streaming.StreamingNodeMetrics.wals:type_name -> milvus.proto.streaming.StreamingNodeWALMetrics + 7, // 76: milvus.proto.streaming.StreamingNodeWALMetrics.info:type_name -> milvus.proto.streaming.PChannelInfo + 72, // 77: milvus.proto.streaming.StreamingNodeWALMetrics.rw:type_name -> milvus.proto.streaming.StreamingNodeRWWALMetrics + 73, // 78: milvus.proto.streaming.StreamingNodeWALMetrics.ro:type_name -> milvus.proto.streaming.StreamingNodeROWALMetrics + 70, // 79: milvus.proto.streaming.StreamingNodeManagerCollectStatusResponse.metrics:type_name -> milvus.proto.streaming.StreamingNodeMetrics + 4, // 80: milvus.proto.streaming.VChannelMeta.state:type_name -> milvus.proto.streaming.VChannelState + 76, // 81: milvus.proto.streaming.VChannelMeta.collection_info:type_name -> milvus.proto.streaming.CollectionInfoOfVChannel + 78, // 82: milvus.proto.streaming.CollectionInfoOfVChannel.partitions:type_name -> milvus.proto.streaming.PartitionInfoOfVChannel + 77, // 83: milvus.proto.streaming.CollectionInfoOfVChannel.schemas:type_name -> milvus.proto.streaming.CollectionSchemaOfVChannel + 95, // 84: milvus.proto.streaming.CollectionSchemaOfVChannel.schema:type_name -> milvus.proto.schema.CollectionSchema + 5, // 85: milvus.proto.streaming.CollectionSchemaOfVChannel.state:type_name -> milvus.proto.streaming.VChannelSchemaState + 6, // 86: milvus.proto.streaming.SegmentAssignmentMeta.state:type_name -> milvus.proto.streaming.SegmentAssignmentState + 80, // 87: milvus.proto.streaming.SegmentAssignmentMeta.stat:type_name -> milvus.proto.streaming.SegmentAssignmentStat + 96, // 88: milvus.proto.streaming.SegmentAssignmentStat.level:type_name -> milvus.proto.data.SegmentLevel + 86, // 89: milvus.proto.streaming.WALCheckpoint.message_id:type_name -> milvus.proto.common.MessageID + 88, // 90: milvus.proto.streaming.WALCheckpoint.replicate_config:type_name -> milvus.proto.common.ReplicateConfiguration + 92, // 91: milvus.proto.streaming.WALCheckpoint.replicate_checkpoint:type_name -> milvus.proto.common.ReplicateCheckpoint + 88, // 92: milvus.proto.streaming.ReplicateConfigurationMeta.replicate_configuration:type_name -> milvus.proto.common.ReplicateConfiguration + 14, // 93: milvus.proto.streaming.ReplicateConfigurationMeta.acked_result:type_name -> milvus.proto.streaming.AckedResult + 97, // 94: milvus.proto.streaming.ReplicatePChannelMeta.target_cluster:type_name -> milvus.proto.common.MilvusCluster + 92, // 95: milvus.proto.streaming.ReplicatePChannelMeta.initialized_checkpoint:type_name -> milvus.proto.common.ReplicateCheckpoint + 50, // 96: milvus.proto.streaming.BroadcastResponse.ResultsEntry.value:type_name -> milvus.proto.streaming.ProduceMessageResponseResult + 98, // 97: milvus.proto.streaming.StreamingNodeStateService.GetComponentStates:input_type -> milvus.proto.milvus.GetComponentStatesRequest + 16, // 98: milvus.proto.streaming.StreamingCoordBroadcastService.Broadcast:input_type -> milvus.proto.streaming.BroadcastRequest + 18, // 99: milvus.proto.streaming.StreamingCoordBroadcastService.Ack:input_type -> milvus.proto.streaming.BroadcastAckRequest + 20, // 100: milvus.proto.streaming.StreamingCoordAssignmentService.UpdateReplicateConfiguration:input_type -> milvus.proto.streaming.UpdateReplicateConfigurationRequest + 22, // 101: milvus.proto.streaming.StreamingCoordAssignmentService.UpdateWALBalancePolicy:input_type -> milvus.proto.streaming.UpdateWALBalancePolicyRequest + 26, // 102: milvus.proto.streaming.StreamingCoordAssignmentService.AssignmentDiscover:input_type -> milvus.proto.streaming.AssignmentDiscoverRequest + 41, // 103: milvus.proto.streaming.StreamingNodeHandlerService.GetReplicateCheckpoint:input_type -> milvus.proto.streaming.GetReplicateCheckpointRequest + 43, // 104: milvus.proto.streaming.StreamingNodeHandlerService.Produce:input_type -> milvus.proto.streaming.ProduceRequest + 52, // 105: milvus.proto.streaming.StreamingNodeHandlerService.Consume:input_type -> milvus.proto.streaming.ConsumeRequest + 65, // 106: milvus.proto.streaming.StreamingNodeManagerService.Assign:input_type -> milvus.proto.streaming.StreamingNodeManagerAssignRequest + 67, // 107: milvus.proto.streaming.StreamingNodeManagerService.Remove:input_type -> milvus.proto.streaming.StreamingNodeManagerRemoveRequest + 69, // 108: milvus.proto.streaming.StreamingNodeManagerService.CollectStatus:input_type -> milvus.proto.streaming.StreamingNodeManagerCollectStatusRequest + 99, // 109: milvus.proto.streaming.StreamingNodeStateService.GetComponentStates:output_type -> milvus.proto.milvus.ComponentStates + 17, // 110: milvus.proto.streaming.StreamingCoordBroadcastService.Broadcast:output_type -> milvus.proto.streaming.BroadcastResponse + 19, // 111: milvus.proto.streaming.StreamingCoordBroadcastService.Ack:output_type -> milvus.proto.streaming.BroadcastAckResponse + 21, // 112: milvus.proto.streaming.StreamingCoordAssignmentService.UpdateReplicateConfiguration:output_type -> milvus.proto.streaming.UpdateReplicateConfigurationResponse + 25, // 113: milvus.proto.streaming.StreamingCoordAssignmentService.UpdateWALBalancePolicy:output_type -> milvus.proto.streaming.UpdateWALBalancePolicyResponse + 29, // 114: milvus.proto.streaming.StreamingCoordAssignmentService.AssignmentDiscover:output_type -> milvus.proto.streaming.AssignmentDiscoverResponse + 42, // 115: milvus.proto.streaming.StreamingNodeHandlerService.GetReplicateCheckpoint:output_type -> milvus.proto.streaming.GetReplicateCheckpointResponse + 47, // 116: milvus.proto.streaming.StreamingNodeHandlerService.Produce:output_type -> milvus.proto.streaming.ProduceResponse + 61, // 117: milvus.proto.streaming.StreamingNodeHandlerService.Consume:output_type -> milvus.proto.streaming.ConsumeResponse + 66, // 118: milvus.proto.streaming.StreamingNodeManagerService.Assign:output_type -> milvus.proto.streaming.StreamingNodeManagerAssignResponse + 68, // 119: milvus.proto.streaming.StreamingNodeManagerService.Remove:output_type -> milvus.proto.streaming.StreamingNodeManagerRemoveResponse + 74, // 120: milvus.proto.streaming.StreamingNodeManagerService.CollectStatus:output_type -> milvus.proto.streaming.StreamingNodeManagerCollectStatusResponse + 109, // [109:121] is the sub-list for method output_type + 97, // [97:109] is the sub-list for method input_type + 97, // [97:97] is the sub-list for extension type_name + 97, // [97:97] is the sub-list for extension extendee + 0, // [0:97] is the sub-list for field type_name } func init() { file_streaming_proto_init() } @@ -5779,7 +6385,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BroadcastRequest); i { + switch v := v.(*AckedResult); i { case 0: return &v.state case 1: @@ -5791,7 +6397,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BroadcastResponse); i { + switch v := v.(*AckedCheckpoint); i { case 0: return &v.state case 1: @@ -5803,7 +6409,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BroadcastAckRequest); i { + switch v := v.(*BroadcastRequest); i { case 0: return &v.state case 1: @@ -5815,7 +6421,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BroadcastAckResponse); i { + switch v := v.(*BroadcastResponse); i { case 0: return &v.state case 1: @@ -5827,7 +6433,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UpdateWALBalancePolicyRequest); i { + switch v := v.(*BroadcastAckRequest); i { case 0: return &v.state case 1: @@ -5839,7 +6445,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*WALBalancePolicyConfig); i { + switch v := v.(*BroadcastAckResponse); i { case 0: return &v.state case 1: @@ -5851,7 +6457,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*WALBalancePolicyNodes); i { + switch v := v.(*UpdateReplicateConfigurationRequest); i { case 0: return &v.state case 1: @@ -5863,7 +6469,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UpdateWALBalancePolicyResponse); i { + switch v := v.(*UpdateReplicateConfigurationResponse); i { case 0: return &v.state case 1: @@ -5875,7 +6481,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AssignmentDiscoverRequest); i { + switch v := v.(*UpdateWALBalancePolicyRequest); i { case 0: return &v.state case 1: @@ -5887,7 +6493,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ReportAssignmentErrorRequest); i { + switch v := v.(*WALBalancePolicyConfig); i { case 0: return &v.state case 1: @@ -5899,7 +6505,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CloseAssignmentDiscoverRequest); i { + switch v := v.(*WALBalancePolicyNodes); i { case 0: return &v.state case 1: @@ -5911,7 +6517,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AssignmentDiscoverResponse); i { + switch v := v.(*UpdateWALBalancePolicyResponse); i { case 0: return &v.state case 1: @@ -5923,7 +6529,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FullStreamingNodeAssignmentWithVersion); i { + switch v := v.(*AssignmentDiscoverRequest); i { case 0: return &v.state case 1: @@ -5935,7 +6541,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CChannelAssignment); i { + switch v := v.(*ReportAssignmentErrorRequest); i { case 0: return &v.state case 1: @@ -5947,7 +6553,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CloseAssignmentDiscoverResponse); i { + switch v := v.(*CloseAssignmentDiscoverRequest); i { case 0: return &v.state case 1: @@ -5959,7 +6565,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StreamingNodeInfo); i { + switch v := v.(*AssignmentDiscoverResponse); i { case 0: return &v.state case 1: @@ -5971,7 +6577,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StreamingNodeAssignment); i { + switch v := v.(*FullStreamingNodeAssignmentWithVersion); i { case 0: return &v.state case 1: @@ -5983,7 +6589,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DeliverPolicy); i { + switch v := v.(*CChannelAssignment); i { case 0: return &v.state case 1: @@ -5995,7 +6601,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DeliverFilter); i { + switch v := v.(*CloseAssignmentDiscoverResponse); i { case 0: return &v.state case 1: @@ -6007,7 +6613,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DeliverFilterTimeTickGT); i { + switch v := v.(*StreamingNodeInfo); i { case 0: return &v.state case 1: @@ -6019,7 +6625,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DeliverFilterTimeTickGTE); i { + switch v := v.(*StreamingNodeAssignment); i { case 0: return &v.state case 1: @@ -6031,7 +6637,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DeliverFilterMessageType); i { + switch v := v.(*DeliverPolicy); i { case 0: return &v.state case 1: @@ -6043,7 +6649,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StreamingError); i { + switch v := v.(*DeliverFilter); i { case 0: return &v.state case 1: @@ -6055,7 +6661,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ProduceRequest); i { + switch v := v.(*DeliverFilterTimeTickGT); i { case 0: return &v.state case 1: @@ -6067,7 +6673,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CreateProducerRequest); i { + switch v := v.(*DeliverFilterTimeTickGTE); i { case 0: return &v.state case 1: @@ -6079,7 +6685,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ProduceMessageRequest); i { + switch v := v.(*DeliverFilterMessageType); i { case 0: return &v.state case 1: @@ -6091,7 +6697,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CloseProducerRequest); i { + switch v := v.(*StreamingError); i { case 0: return &v.state case 1: @@ -6103,7 +6709,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ProduceResponse); i { + switch v := v.(*GetReplicateCheckpointRequest); i { case 0: return &v.state case 1: @@ -6115,7 +6721,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CreateProducerResponse); i { + switch v := v.(*GetReplicateCheckpointResponse); i { case 0: return &v.state case 1: @@ -6127,7 +6733,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[36].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ProduceMessageResponse); i { + switch v := v.(*ProduceRequest); i { case 0: return &v.state case 1: @@ -6139,7 +6745,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[37].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ProduceMessageResponseResult); i { + switch v := v.(*CreateProducerRequest); i { case 0: return &v.state case 1: @@ -6151,7 +6757,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[38].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CloseProducerResponse); i { + switch v := v.(*ProduceMessageRequest); i { case 0: return &v.state case 1: @@ -6163,7 +6769,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[39].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ConsumeRequest); i { + switch v := v.(*CloseProducerRequest); i { case 0: return &v.state case 1: @@ -6175,7 +6781,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[40].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CloseConsumerRequest); i { + switch v := v.(*ProduceResponse); i { case 0: return &v.state case 1: @@ -6187,7 +6793,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[41].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CreateConsumerRequest); i { + switch v := v.(*CreateProducerResponse); i { case 0: return &v.state case 1: @@ -6199,7 +6805,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[42].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CreateVChannelConsumersRequest); i { + switch v := v.(*ProduceMessageResponse); i { case 0: return &v.state case 1: @@ -6211,7 +6817,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[43].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CreateVChannelConsumerRequest); i { + switch v := v.(*ProduceMessageResponseResult); i { case 0: return &v.state case 1: @@ -6223,7 +6829,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[44].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CreateVChannelConsumersResponse); i { + switch v := v.(*CloseProducerResponse); i { case 0: return &v.state case 1: @@ -6235,7 +6841,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[45].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CreateVChannelConsumerResponse); i { + switch v := v.(*ConsumeRequest); i { case 0: return &v.state case 1: @@ -6247,7 +6853,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[46].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CloseVChannelConsumerRequest); i { + switch v := v.(*CloseConsumerRequest); i { case 0: return &v.state case 1: @@ -6259,7 +6865,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[47].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CloseVChannelConsumerResponse); i { + switch v := v.(*CreateConsumerRequest); i { case 0: return &v.state case 1: @@ -6271,7 +6877,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[48].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ConsumeResponse); i { + switch v := v.(*CreateVChannelConsumersRequest); i { case 0: return &v.state case 1: @@ -6283,7 +6889,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[49].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CreateConsumerResponse); i { + switch v := v.(*CreateVChannelConsumerRequest); i { case 0: return &v.state case 1: @@ -6295,7 +6901,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[50].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ConsumeMessageReponse); i { + switch v := v.(*CreateVChannelConsumersResponse); i { case 0: return &v.state case 1: @@ -6307,7 +6913,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[51].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CloseConsumerResponse); i { + switch v := v.(*CreateVChannelConsumerResponse); i { case 0: return &v.state case 1: @@ -6319,7 +6925,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[52].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StreamingNodeManagerAssignRequest); i { + switch v := v.(*CloseVChannelConsumerRequest); i { case 0: return &v.state case 1: @@ -6331,7 +6937,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[53].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StreamingNodeManagerAssignResponse); i { + switch v := v.(*CloseVChannelConsumerResponse); i { case 0: return &v.state case 1: @@ -6343,7 +6949,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[54].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StreamingNodeManagerRemoveRequest); i { + switch v := v.(*ConsumeResponse); i { case 0: return &v.state case 1: @@ -6355,7 +6961,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[55].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StreamingNodeManagerRemoveResponse); i { + switch v := v.(*CreateConsumerResponse); i { case 0: return &v.state case 1: @@ -6367,7 +6973,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[56].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StreamingNodeManagerCollectStatusRequest); i { + switch v := v.(*ConsumeMessageReponse); i { case 0: return &v.state case 1: @@ -6379,7 +6985,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[57].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StreamingNodeMetrics); i { + switch v := v.(*CloseConsumerResponse); i { case 0: return &v.state case 1: @@ -6391,7 +6997,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[58].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StreamingNodeWALMetrics); i { + switch v := v.(*StreamingNodeManagerAssignRequest); i { case 0: return &v.state case 1: @@ -6403,7 +7009,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[59].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StreamingNodeRWWALMetrics); i { + switch v := v.(*StreamingNodeManagerAssignResponse); i { case 0: return &v.state case 1: @@ -6415,7 +7021,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[60].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StreamingNodeROWALMetrics); i { + switch v := v.(*StreamingNodeManagerRemoveRequest); i { case 0: return &v.state case 1: @@ -6427,7 +7033,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[61].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StreamingNodeManagerCollectStatusResponse); i { + switch v := v.(*StreamingNodeManagerRemoveResponse); i { case 0: return &v.state case 1: @@ -6439,7 +7045,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[62].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*VChannelMeta); i { + switch v := v.(*StreamingNodeManagerCollectStatusRequest); i { case 0: return &v.state case 1: @@ -6451,7 +7057,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[63].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CollectionInfoOfVChannel); i { + switch v := v.(*StreamingNodeMetrics); i { case 0: return &v.state case 1: @@ -6463,7 +7069,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[64].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CollectionSchemaOfVChannel); i { + switch v := v.(*StreamingNodeWALMetrics); i { case 0: return &v.state case 1: @@ -6475,7 +7081,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[65].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PartitionInfoOfVChannel); i { + switch v := v.(*StreamingNodeRWWALMetrics); i { case 0: return &v.state case 1: @@ -6487,7 +7093,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[66].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SegmentAssignmentMeta); i { + switch v := v.(*StreamingNodeROWALMetrics); i { case 0: return &v.state case 1: @@ -6499,7 +7105,7 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[67].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SegmentAssignmentStat); i { + switch v := v.(*StreamingNodeManagerCollectStatusResponse); i { case 0: return &v.state case 1: @@ -6511,6 +7117,78 @@ func file_streaming_proto_init() { } } file_streaming_proto_msgTypes[68].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*VChannelMeta); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_streaming_proto_msgTypes[69].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CollectionInfoOfVChannel); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_streaming_proto_msgTypes[70].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CollectionSchemaOfVChannel); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_streaming_proto_msgTypes[71].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PartitionInfoOfVChannel); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_streaming_proto_msgTypes[72].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SegmentAssignmentMeta); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_streaming_proto_msgTypes[73].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SegmentAssignmentStat); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_streaming_proto_msgTypes[74].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*WALCheckpoint); i { case 0: return &v.state @@ -6522,50 +7200,74 @@ func file_streaming_proto_init() { return nil } } + file_streaming_proto_msgTypes[75].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ReplicateConfigurationMeta); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_streaming_proto_msgTypes[76].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ReplicatePChannelMeta); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } - file_streaming_proto_msgTypes[15].OneofWrappers = []interface{}{ + file_streaming_proto_msgTypes[19].OneofWrappers = []interface{}{ (*AssignmentDiscoverRequest_ReportError)(nil), (*AssignmentDiscoverRequest_Close)(nil), } - file_streaming_proto_msgTypes[18].OneofWrappers = []interface{}{ + file_streaming_proto_msgTypes[22].OneofWrappers = []interface{}{ (*AssignmentDiscoverResponse_FullAssignment)(nil), (*AssignmentDiscoverResponse_Close)(nil), } - file_streaming_proto_msgTypes[24].OneofWrappers = []interface{}{ + file_streaming_proto_msgTypes[28].OneofWrappers = []interface{}{ (*DeliverPolicy_All)(nil), (*DeliverPolicy_Latest)(nil), (*DeliverPolicy_StartFrom)(nil), (*DeliverPolicy_StartAfter)(nil), } - file_streaming_proto_msgTypes[25].OneofWrappers = []interface{}{ + file_streaming_proto_msgTypes[29].OneofWrappers = []interface{}{ (*DeliverFilter_TimeTickGt)(nil), (*DeliverFilter_TimeTickGte)(nil), (*DeliverFilter_MessageType)(nil), } - file_streaming_proto_msgTypes[30].OneofWrappers = []interface{}{ + file_streaming_proto_msgTypes[36].OneofWrappers = []interface{}{ (*ProduceRequest_Produce)(nil), (*ProduceRequest_Close)(nil), } - file_streaming_proto_msgTypes[34].OneofWrappers = []interface{}{ + file_streaming_proto_msgTypes[40].OneofWrappers = []interface{}{ (*ProduceResponse_Create)(nil), (*ProduceResponse_Produce)(nil), (*ProduceResponse_Close)(nil), } - file_streaming_proto_msgTypes[36].OneofWrappers = []interface{}{ + file_streaming_proto_msgTypes[42].OneofWrappers = []interface{}{ (*ProduceMessageResponse_Result)(nil), (*ProduceMessageResponse_Error)(nil), } - file_streaming_proto_msgTypes[39].OneofWrappers = []interface{}{ + file_streaming_proto_msgTypes[45].OneofWrappers = []interface{}{ (*ConsumeRequest_CreateVchannelConsumer)(nil), (*ConsumeRequest_CreateVchannelConsumers)(nil), (*ConsumeRequest_CloseVchannel)(nil), (*ConsumeRequest_Close)(nil), } - file_streaming_proto_msgTypes[45].OneofWrappers = []interface{}{ + file_streaming_proto_msgTypes[51].OneofWrappers = []interface{}{ (*CreateVChannelConsumerResponse_ConsumerId)(nil), (*CreateVChannelConsumerResponse_Error)(nil), } - file_streaming_proto_msgTypes[48].OneofWrappers = []interface{}{ + file_streaming_proto_msgTypes[54].OneofWrappers = []interface{}{ (*ConsumeResponse_Create)(nil), (*ConsumeResponse_Consume)(nil), (*ConsumeResponse_CreateVchannel)(nil), @@ -6573,7 +7275,7 @@ func file_streaming_proto_init() { (*ConsumeResponse_CloseVchannel)(nil), (*ConsumeResponse_Close)(nil), } - file_streaming_proto_msgTypes[58].OneofWrappers = []interface{}{ + file_streaming_proto_msgTypes[64].OneofWrappers = []interface{}{ (*StreamingNodeWALMetrics_Rw)(nil), (*StreamingNodeWALMetrics_Ro)(nil), } @@ -6583,7 +7285,7 @@ func file_streaming_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_streaming_proto_rawDesc, NumEnums: 7, - NumMessages: 70, + NumMessages: 78, NumExtensions: 0, NumServices: 5, }, diff --git a/pkg/proto/streamingpb/streaming_grpc.pb.go b/pkg/proto/streamingpb/streaming_grpc.pb.go index 8b2a8cf6f7..3f3d2319d6 100644 --- a/pkg/proto/streamingpb/streaming_grpc.pb.go +++ b/pkg/proto/streamingpb/streaming_grpc.pb.go @@ -239,14 +239,26 @@ var StreamingCoordBroadcastService_ServiceDesc = grpc.ServiceDesc{ } const ( - StreamingCoordAssignmentService_UpdateWALBalancePolicy_FullMethodName = "/milvus.proto.streaming.StreamingCoordAssignmentService/UpdateWALBalancePolicy" - StreamingCoordAssignmentService_AssignmentDiscover_FullMethodName = "/milvus.proto.streaming.StreamingCoordAssignmentService/AssignmentDiscover" + StreamingCoordAssignmentService_UpdateReplicateConfiguration_FullMethodName = "/milvus.proto.streaming.StreamingCoordAssignmentService/UpdateReplicateConfiguration" + StreamingCoordAssignmentService_UpdateWALBalancePolicy_FullMethodName = "/milvus.proto.streaming.StreamingCoordAssignmentService/UpdateWALBalancePolicy" + StreamingCoordAssignmentService_AssignmentDiscover_FullMethodName = "/milvus.proto.streaming.StreamingCoordAssignmentService/AssignmentDiscover" ) // StreamingCoordAssignmentServiceClient is the client API for StreamingCoordAssignmentService service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. type StreamingCoordAssignmentServiceClient interface { + // UpdateReplicateConfiguration applies a full replacement of the current + // replication configuration across Milvus clusters. + // + // Semantics: + // - The provided ReplicateConfiguration completely replaces any existing + // configuration persisted in the metadata store. + // - Passing an empty ReplicateConfiguration is treated as a "clear" + // operation, effectively removing all replication configuration. + // - The RPC is expected to be idempotent: submitting the same configuration + // multiple times must not cause side effects. + UpdateReplicateConfiguration(ctx context.Context, in *UpdateReplicateConfigurationRequest, opts ...grpc.CallOption) (*UpdateReplicateConfigurationResponse, error) // UpdateWALBalancePolicy is used to update the WAL balance policy. // The policy is used to control the balance of the WAL. UpdateWALBalancePolicy(ctx context.Context, in *UpdateWALBalancePolicyRequest, opts ...grpc.CallOption) (*UpdateWALBalancePolicyResponse, error) @@ -264,6 +276,15 @@ func NewStreamingCoordAssignmentServiceClient(cc grpc.ClientConnInterface) Strea return &streamingCoordAssignmentServiceClient{cc} } +func (c *streamingCoordAssignmentServiceClient) UpdateReplicateConfiguration(ctx context.Context, in *UpdateReplicateConfigurationRequest, opts ...grpc.CallOption) (*UpdateReplicateConfigurationResponse, error) { + out := new(UpdateReplicateConfigurationResponse) + err := c.cc.Invoke(ctx, StreamingCoordAssignmentService_UpdateReplicateConfiguration_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *streamingCoordAssignmentServiceClient) UpdateWALBalancePolicy(ctx context.Context, in *UpdateWALBalancePolicyRequest, opts ...grpc.CallOption) (*UpdateWALBalancePolicyResponse, error) { out := new(UpdateWALBalancePolicyResponse) err := c.cc.Invoke(ctx, StreamingCoordAssignmentService_UpdateWALBalancePolicy_FullMethodName, in, out, opts...) @@ -308,6 +329,17 @@ func (x *streamingCoordAssignmentServiceAssignmentDiscoverClient) Recv() (*Assig // All implementations should embed UnimplementedStreamingCoordAssignmentServiceServer // for forward compatibility type StreamingCoordAssignmentServiceServer interface { + // UpdateReplicateConfiguration applies a full replacement of the current + // replication configuration across Milvus clusters. + // + // Semantics: + // - The provided ReplicateConfiguration completely replaces any existing + // configuration persisted in the metadata store. + // - Passing an empty ReplicateConfiguration is treated as a "clear" + // operation, effectively removing all replication configuration. + // - The RPC is expected to be idempotent: submitting the same configuration + // multiple times must not cause side effects. + UpdateReplicateConfiguration(context.Context, *UpdateReplicateConfigurationRequest) (*UpdateReplicateConfigurationResponse, error) // UpdateWALBalancePolicy is used to update the WAL balance policy. // The policy is used to control the balance of the WAL. UpdateWALBalancePolicy(context.Context, *UpdateWALBalancePolicyRequest) (*UpdateWALBalancePolicyResponse, error) @@ -321,6 +353,9 @@ type StreamingCoordAssignmentServiceServer interface { type UnimplementedStreamingCoordAssignmentServiceServer struct { } +func (UnimplementedStreamingCoordAssignmentServiceServer) UpdateReplicateConfiguration(context.Context, *UpdateReplicateConfigurationRequest) (*UpdateReplicateConfigurationResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateReplicateConfiguration not implemented") +} func (UnimplementedStreamingCoordAssignmentServiceServer) UpdateWALBalancePolicy(context.Context, *UpdateWALBalancePolicyRequest) (*UpdateWALBalancePolicyResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method UpdateWALBalancePolicy not implemented") } @@ -339,6 +374,24 @@ func RegisterStreamingCoordAssignmentServiceServer(s grpc.ServiceRegistrar, srv s.RegisterService(&StreamingCoordAssignmentService_ServiceDesc, srv) } +func _StreamingCoordAssignmentService_UpdateReplicateConfiguration_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateReplicateConfigurationRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StreamingCoordAssignmentServiceServer).UpdateReplicateConfiguration(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: StreamingCoordAssignmentService_UpdateReplicateConfiguration_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StreamingCoordAssignmentServiceServer).UpdateReplicateConfiguration(ctx, req.(*UpdateReplicateConfigurationRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _StreamingCoordAssignmentService_UpdateWALBalancePolicy_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(UpdateWALBalancePolicyRequest) if err := dec(in); err != nil { @@ -390,6 +443,10 @@ var StreamingCoordAssignmentService_ServiceDesc = grpc.ServiceDesc{ ServiceName: "milvus.proto.streaming.StreamingCoordAssignmentService", HandlerType: (*StreamingCoordAssignmentServiceServer)(nil), Methods: []grpc.MethodDesc{ + { + MethodName: "UpdateReplicateConfiguration", + Handler: _StreamingCoordAssignmentService_UpdateReplicateConfiguration_Handler, + }, { MethodName: "UpdateWALBalancePolicy", Handler: _StreamingCoordAssignmentService_UpdateWALBalancePolicy_Handler, @@ -407,14 +464,18 @@ var StreamingCoordAssignmentService_ServiceDesc = grpc.ServiceDesc{ } const ( - StreamingNodeHandlerService_Produce_FullMethodName = "/milvus.proto.streaming.StreamingNodeHandlerService/Produce" - StreamingNodeHandlerService_Consume_FullMethodName = "/milvus.proto.streaming.StreamingNodeHandlerService/Consume" + StreamingNodeHandlerService_GetReplicateCheckpoint_FullMethodName = "/milvus.proto.streaming.StreamingNodeHandlerService/GetReplicateCheckpoint" + StreamingNodeHandlerService_Produce_FullMethodName = "/milvus.proto.streaming.StreamingNodeHandlerService/Produce" + StreamingNodeHandlerService_Consume_FullMethodName = "/milvus.proto.streaming.StreamingNodeHandlerService/Consume" ) // StreamingNodeHandlerServiceClient is the client API for StreamingNodeHandlerService service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. type StreamingNodeHandlerServiceClient interface { + // GetReplicateCheckpoint returns the WAL checkpoint that will be used to create scanner + // from the correct position, ensuring no duplicate or missing messages. + GetReplicateCheckpoint(ctx context.Context, in *GetReplicateCheckpointRequest, opts ...grpc.CallOption) (*GetReplicateCheckpointResponse, error) // Produce is a bi-directional streaming RPC to send messages to a channel. // All messages sent to a channel will be assigned a unique messageID. // The messageID is used to identify the message in the channel. @@ -440,6 +501,15 @@ func NewStreamingNodeHandlerServiceClient(cc grpc.ClientConnInterface) Streaming return &streamingNodeHandlerServiceClient{cc} } +func (c *streamingNodeHandlerServiceClient) GetReplicateCheckpoint(ctx context.Context, in *GetReplicateCheckpointRequest, opts ...grpc.CallOption) (*GetReplicateCheckpointResponse, error) { + out := new(GetReplicateCheckpointResponse) + err := c.cc.Invoke(ctx, StreamingNodeHandlerService_GetReplicateCheckpoint_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *streamingNodeHandlerServiceClient) Produce(ctx context.Context, opts ...grpc.CallOption) (StreamingNodeHandlerService_ProduceClient, error) { stream, err := c.cc.NewStream(ctx, &StreamingNodeHandlerService_ServiceDesc.Streams[0], StreamingNodeHandlerService_Produce_FullMethodName, opts...) if err != nil { @@ -506,6 +576,9 @@ func (x *streamingNodeHandlerServiceConsumeClient) Recv() (*ConsumeResponse, err // All implementations should embed UnimplementedStreamingNodeHandlerServiceServer // for forward compatibility type StreamingNodeHandlerServiceServer interface { + // GetReplicateCheckpoint returns the WAL checkpoint that will be used to create scanner + // from the correct position, ensuring no duplicate or missing messages. + GetReplicateCheckpoint(context.Context, *GetReplicateCheckpointRequest) (*GetReplicateCheckpointResponse, error) // Produce is a bi-directional streaming RPC to send messages to a channel. // All messages sent to a channel will be assigned a unique messageID. // The messageID is used to identify the message in the channel. @@ -527,6 +600,9 @@ type StreamingNodeHandlerServiceServer interface { type UnimplementedStreamingNodeHandlerServiceServer struct { } +func (UnimplementedStreamingNodeHandlerServiceServer) GetReplicateCheckpoint(context.Context, *GetReplicateCheckpointRequest) (*GetReplicateCheckpointResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetReplicateCheckpoint not implemented") +} func (UnimplementedStreamingNodeHandlerServiceServer) Produce(StreamingNodeHandlerService_ProduceServer) error { return status.Errorf(codes.Unimplemented, "method Produce not implemented") } @@ -545,6 +621,24 @@ func RegisterStreamingNodeHandlerServiceServer(s grpc.ServiceRegistrar, srv Stre s.RegisterService(&StreamingNodeHandlerService_ServiceDesc, srv) } +func _StreamingNodeHandlerService_GetReplicateCheckpoint_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetReplicateCheckpointRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StreamingNodeHandlerServiceServer).GetReplicateCheckpoint(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: StreamingNodeHandlerService_GetReplicateCheckpoint_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StreamingNodeHandlerServiceServer).GetReplicateCheckpoint(ctx, req.(*GetReplicateCheckpointRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _StreamingNodeHandlerService_Produce_Handler(srv interface{}, stream grpc.ServerStream) error { return srv.(StreamingNodeHandlerServiceServer).Produce(&streamingNodeHandlerServiceProduceServer{stream}) } @@ -603,7 +697,12 @@ func (x *streamingNodeHandlerServiceConsumeServer) Recv() (*ConsumeRequest, erro var StreamingNodeHandlerService_ServiceDesc = grpc.ServiceDesc{ ServiceName: "milvus.proto.streaming.StreamingNodeHandlerService", HandlerType: (*StreamingNodeHandlerServiceServer)(nil), - Methods: []grpc.MethodDesc{}, + Methods: []grpc.MethodDesc{ + { + MethodName: "GetReplicateCheckpoint", + Handler: _StreamingNodeHandlerService_GetReplicateCheckpoint_Handler, + }, + }, Streams: []grpc.StreamDesc{ { StreamName: "Produce", diff --git a/pkg/streaming/util/message/adaptor/message_id.go b/pkg/streaming/util/message/adaptor/message_id.go index 227fbf831e..255c7f134d 100644 --- a/pkg/streaming/util/message/adaptor/message_id.go +++ b/pkg/streaming/util/message/adaptor/message_id.go @@ -7,6 +7,7 @@ import ( rawKafka "github.com/confluentinc/confluent-kafka-go/kafka" "github.com/zilliztech/woodpecker/woodpecker/log" + "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" "github.com/milvus-io/milvus/pkg/v2/mq/common" "github.com/milvus-io/milvus/pkg/v2/mq/mqimpl/rocksmq/server" mqkafka "github.com/milvus-io/milvus/pkg/v2/mq/msgstream/mqwrapper/kafka" @@ -53,19 +54,19 @@ func MustGetMessageIDFromMQWrapperID(commonMessageID common.MessageID) message.M // TODO: should be removed in future after common.MessageID is removed func DeserializeToMQWrapperID(msgID []byte, walName string) (common.MessageID, error) { switch walName { - case "pulsar": + case "pulsar", commonpb.WALName_Pulsar.String(): pulsarID, err := mqpulsar.DeserializePulsarMsgID(msgID) if err != nil { return nil, err } return mqpulsar.NewPulsarID(pulsarID), nil - case "rocksmq": + case "rocksmq", commonpb.WALName_RocksMQ.String(): rID := server.DeserializeRmqID(msgID) return &server.RmqID{MessageID: rID}, nil - case "kafka": + case "kafka", commonpb.WALName_Kafka.String(): kID := mqkafka.DeserializeKafkaID(msgID) return mqkafka.NewKafkaID(kID), nil - case "woodpecker": + case "woodpecker", commonpb.WALName_WoodPecker.String(): wID, err := mqwoodpecker.DeserializeWoodpeckerMsgID(msgID) if err != nil { return nil, err @@ -76,22 +77,23 @@ func DeserializeToMQWrapperID(msgID []byte, walName string) (common.MessageID, e } } -func MustGetMessageIDFromMQWrapperIDBytes(walName string, msgIDBytes []byte) message.MessageID { +func MustGetMessageIDFromMQWrapperIDBytes(msgIDBytes []byte) message.MessageID { + walName := message.MustGetDefaultWALName() var commonMsgID common.MessageID switch walName { - case "rocksmq": + case message.WALNameRocksmq: id := server.DeserializeRmqID(msgIDBytes) commonMsgID = &server.RmqID{MessageID: id} - case "pulsar": + case message.WALNamePulsar: msgID, err := mqpulsar.DeserializePulsarMsgID(msgIDBytes) if err != nil { panic(err) } commonMsgID = mqpulsar.NewPulsarID(msgID) - case "kafka": + case message.WALNameKafka: id := mqkafka.DeserializeKafkaID(msgIDBytes) commonMsgID = mqkafka.NewKafkaID(id) - case "woodpecker": + case message.WALNameWoodpecker: msgID, err := mqwoodpecker.DeserializeWoodpeckerMsgID(msgIDBytes) if err != nil { panic(err) diff --git a/pkg/streaming/util/message/builder.go b/pkg/streaming/util/message/builder.go index 4f0a1cfba2..c6e198119d 100644 --- a/pkg/streaming/util/message/builder.go +++ b/pkg/streaming/util/message/builder.go @@ -8,6 +8,7 @@ import ( "github.com/cockroachdb/errors" "google.golang.org/protobuf/proto" + "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" "github.com/milvus-io/milvus/pkg/v2/proto/messagespb" "github.com/milvus-io/milvus/pkg/v2/util/tsoutil" "github.com/milvus-io/milvus/pkg/v2/util/typeutil" @@ -36,20 +37,6 @@ func NewBroadcastMutableMessageBeforeAppend(payload []byte, properties map[strin return m } -// NewImmutableMessageFromProto creates a new immutable message from the proto message. -// !!! Only used at server side for streaming internal service, don't use it at client side. -func NewImmutableMessageFromProto(walName string, msg *messagespb.ImmutableMessage) ImmutableMessage { - id, err := UnmarshalMessageID(walName, msg.Id.Id) - if err != nil { - panic(err) - } - return NewImmutableMesasge( - id, - msg.Payload, - msg.Properties, - ) -} - // NewImmutableMessage creates a new immutable message. // !!! Only used at server side for streaming internal service, don't use it at client side. func NewImmutableMesasge( @@ -66,6 +53,47 @@ func NewImmutableMesasge( } } +// NewReplicateMessage creates a new replicate message. +func NewReplicateMessage(clustrID string, im *commonpb.ImmutableMessage) ReplicateMutableMessage { + messageID := MustUnmarshalMessageID(im.GetId()) + msg := NewImmutableMesasge(messageID, im.GetPayload(), im.GetProperties()).(*immutableMessageImpl) + rh, err := EncodeProto(&messagespb.ReplicateHeader{ + ClusterId: clustrID, + MessageId: msg.MessageID().IntoProto(), + LastConfirmedMessageId: msg.LastConfirmedMessageID().IntoProto(), + TimeTick: msg.TimeTick(), + Vchannel: msg.VChannel(), + }) + if err != nil { + panic("failed to encode replicate header") + } + m := &messageImpl{ + payload: msg.payload, + properties: msg.properties.Clone(), + } + m.properties.Delete(messageLastConfirmedIDSameWithMessageID) + m.properties.Delete(messageTimeTick) + m.properties.Delete(messageLastConfirmed) + m.properties.Delete(messageWALTerm) + m.properties.Set(messageReplicateMesssageHeader, rh) + return m +} + +func MilvusMessageToImmutableMessage(im *commonpb.ImmutableMessage) ImmutableMessage { + messageID := MustUnmarshalMessageID(im.GetId()) + msg := NewImmutableMesasge(messageID, im.GetPayload(), im.GetProperties()) + return msg +} + +func ImmutableMessageToMilvusMessage(walName string, im ImmutableMessage) *commonpb.ImmutableMessage { + msg := im.IntoImmutableMessageProto() + return &commonpb.ImmutableMessage{ + Id: im.MessageID().IntoProto(), + Payload: msg.GetPayload(), + Properties: msg.GetProperties(), + } +} + // newMutableMessageBuilder creates a new builder. // Should only used at client side. func newMutableMessageBuilder[H proto.Message, B proto.Message]() *mutableMesasgeBuilder[H, B] { diff --git a/pkg/streaming/util/message/builder_test.go b/pkg/streaming/util/message/builder_test.go index ed05ce44d9..afca9fcc7c 100644 --- a/pkg/streaming/util/message/builder_test.go +++ b/pkg/streaming/util/message/builder_test.go @@ -83,3 +83,30 @@ func TestImmutableTxnBuilder(t *testing.T) { assert.NoError(t, err) log.Info("test", zap.Object("msg", immutableTxnMsg)) } + +func TestReplicateBuilder(t *testing.T) { + msg := message.NewManualFlushMessageBuilderV2(). + WithHeader(&message.ManualFlushMessageHeader{}). + WithBody(&message.ManualFlushMessageBody{}). + WithBroadcast([]string{"v1", "v2"}). + MustBuildBroadcast() + + msgs := msg.WithBroadcastID(1).SplitIntoMutableMessage() + + msgID := walimplstest.NewTestMessageID(1) + immutableMsg := msgs[0].WithTimeTick(100).WithLastConfirmed(msgID).IntoImmutableMessage(msgID) + + replicateMsg := message.NewReplicateMessage("by-dev", immutableMsg.IntoImmutableMessageProto()) + assert.NotNil(t, replicateMsg) + assert.Equal(t, "by-dev", replicateMsg.ReplicateHeader().ClusterID) + assert.Equal(t, uint64(100), replicateMsg.ReplicateHeader().TimeTick) + assert.Equal(t, "v1", replicateMsg.ReplicateHeader().VChannel) + assert.Equal(t, "v1", replicateMsg.VChannel()) + assert.True(t, msgID.EQ(replicateMsg.ReplicateHeader().MessageID)) + assert.True(t, msgID.EQ(replicateMsg.ReplicateHeader().LastConfirmedMessageID)) + + replicateMsg.OverwriteReplicateVChannel("v11", []string{"v11", "v12"}) + assert.Equal(t, "v11", replicateMsg.VChannel()) + assert.Equal(t, []string{"v11", "v12"}, replicateMsg.BroadcastHeader().VChannels) + assert.Equal(t, uint64(1), replicateMsg.BroadcastHeader().BroadcastID) +} diff --git a/pkg/streaming/util/message/codegen/reflect_info.json b/pkg/streaming/util/message/codegen/reflect_info.json index d0cbf17741..44c881c836 100644 --- a/pkg/streaming/util/message/codegen/reflect_info.json +++ b/pkg/streaming/util/message/codegen/reflect_info.json @@ -119,6 +119,16 @@ "Version": 2 } }, + { + "MessageSpecializedType": { + "HeaderType": "messagespb.PutReplicateConfigMessageHeader", + "BodyType": "messagespb.PutReplicateConfigMessageBody" + }, + "MessageTypeWithVersion": { + "MessageType": "MessageTypePutReplicateConfig", + "Version": 2 + } + }, { "MessageSpecializedType": { "HeaderType": "messagespb.BeginTxnMessageHeader", diff --git a/pkg/streaming/util/message/marshal_log_object.go b/pkg/streaming/util/message/marshal_log_object.go index 170824a971..e83c7a8673 100644 --- a/pkg/streaming/util/message/marshal_log_object.go +++ b/pkg/streaming/util/message/marshal_log_object.go @@ -29,6 +29,13 @@ func (m *messageImpl) MarshalLogObject(enc zapcore.ObjectEncoder) error { enc.AddInt64("broadcastID", int64(broadcast.BroadcastID)) enc.AddString("broadcastVChannels", strings.Join(broadcast.VChannels, ",")) } + if replicate := m.ReplicateHeader(); replicate != nil { + enc.AddString("rClusterID", replicate.ClusterID) + enc.AddString("rMessageID", replicate.MessageID.String()) + enc.AddString("rLastConfirmedMessageID", replicate.LastConfirmedMessageID.String()) + enc.AddUint64("rTimeTick", replicate.TimeTick) + enc.AddString("rVchannel", replicate.VChannel) + } enc.AddInt("size", len(m.payload)) marshalSpecializedHeader(m.MessageType(), m.Version(), m.properties[messageHeader], enc) return nil diff --git a/pkg/streaming/util/message/message.go b/pkg/streaming/util/message/message.go index c224de56dd..51ed7e9c50 100644 --- a/pkg/streaming/util/message/message.go +++ b/pkg/streaming/util/message/message.go @@ -4,6 +4,7 @@ import ( "go.uber.org/zap/zapcore" "google.golang.org/protobuf/proto" + "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" "github.com/milvus-io/milvus/pkg/v2/proto/messagespb" ) @@ -59,6 +60,10 @@ type BasicMessage interface { // If the message is not a broadcast message, it will return 0. BroadcastHeader() *BroadcastHeader + // ReplicateHeader returns the replicate header of current message. + // If the message is not a replicate message, it will return nil. + ReplicateHeader() *ReplicateHeader + // IsPersisted returns true if the message is persisted into underlying log storage. IsPersisted() bool @@ -111,6 +116,14 @@ type MutableMessage interface { IntoImmutableMessage(msgID MessageID) ImmutableMessage } +// ReplicateMutableMessage is the replicate message interface. +type ReplicateMutableMessage interface { + MutableMessage + + // OverwriteReplicateVChannel overwrites the vchannel of the replicate message. + OverwriteReplicateVChannel(vchannel string, broadcastVChannels ...[]string) +} + // BroadcastMutableMessage is the broadcast message interface. // Indicated the message is broadcasted on various vchannels. type BroadcastMutableMessage interface { @@ -130,7 +143,7 @@ type ImmutableMessage interface { BasicMessage // WALName returns the name of message related wal. - WALName() string + WALName() WALName // VChannel returns the virtual channel of current message. // Available only when the message's version greater than 0. @@ -148,7 +161,7 @@ type ImmutableMessage interface { LastConfirmedMessageID() MessageID // IntoImmutableMessageProto converts the message to a protobuf immutable message. - IntoImmutableMessageProto() *messagespb.ImmutableMessage + IntoImmutableMessageProto() *commonpb.ImmutableMessage } // ImmutableTxnMessage is the read-only transaction message interface. @@ -210,6 +223,9 @@ type specializedMutableMessage[H proto.Message, B proto.Message] interface { // OverwriteHeader overwrites the message header. OverwriteHeader(header H) + + // OverwriteBody overwrites the message body. + OverwriteBody(body B) } // SpecializedImmutableMessage is the specialized immutable message interface. diff --git a/pkg/streaming/util/message/message_id.go b/pkg/streaming/util/message/message_id.go index fc0f232f74..9497b2922d 100644 --- a/pkg/streaming/util/message/message_id.go +++ b/pkg/streaming/util/message/message_id.go @@ -5,21 +5,22 @@ import ( "github.com/cockroachdb/errors" + "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" "github.com/milvus-io/milvus/pkg/v2/util/typeutil" ) var ( // messageIDUnmarshaler is the map for message id unmarshaler. - messageIDUnmarshaler typeutil.ConcurrentMap[string, MessageIDUnmarshaler] + messageIDUnmarshaler typeutil.ConcurrentMap[WALName, MessageIDUnmarshaler] ErrInvalidMessageID = errors.New("invalid message id") ) // RegisterMessageIDUnmsarshaler register the message id unmarshaler. -func RegisterMessageIDUnmsarshaler(name string, unmarshaler MessageIDUnmarshaler) { - _, loaded := messageIDUnmarshaler.GetOrInsert(name, unmarshaler) +func RegisterMessageIDUnmsarshaler(walName WALName, unmarshaler MessageIDUnmarshaler) { + _, loaded := messageIDUnmarshaler.GetOrInsert(walName, unmarshaler) if loaded { - panic("MessageID Unmarshaler already registered: " + name) + panic("MessageID Unmarshaler already registered: " + walName.String()) } } @@ -27,27 +28,31 @@ func RegisterMessageIDUnmsarshaler(name string, unmarshaler MessageIDUnmarshaler type MessageIDUnmarshaler = func(b string) (MessageID, error) // MustUnmarshalMessageID unmarshal the message id, panic if failed. -func MustUnmarshalMessageID(name string, b string) MessageID { - id, err := UnmarshalMessageID(name, b) +func MustUnmarshalMessageID(msgID *commonpb.MessageID) MessageID { + id, err := UnmarshalMessageID(msgID) if err != nil { - panic(fmt.Sprintf("unmarshal message id failed: %s, wal: %s, bytes: %s", err.Error(), name, b)) + panic(fmt.Sprintf("unmarshal message id failed: %s, wal: %s, bytes: %s", err.Error(), msgID.WALName.String(), msgID.Id)) } return id } // UnmsarshalMessageID unmarshal the message id. -func UnmarshalMessageID(name string, b string) (MessageID, error) { +func UnmarshalMessageID(msgID *commonpb.MessageID) (MessageID, error) { + name := WALName(msgID.WALName) + if name == WALNameUnknown { + name = MustGetDefaultWALName() + } unmarshaler, ok := messageIDUnmarshaler.Get(name) if !ok { - panic("MessageID Unmarshaler not registered: " + name) + panic("MessageID Unmarshaler not registered: " + name.String()) } - return unmarshaler(b) + return unmarshaler(msgID.Id) } // MessageID is the interface for message id. type MessageID interface { // WALName returns the name of message id related wal. - WALName() string + WALName() WALName // LT less than. LT(MessageID) bool @@ -61,6 +66,9 @@ type MessageID interface { // Marshal marshal the message id. Marshal() string + // IntoProto marshal the message id to proto. + IntoProto() *commonpb.MessageID + // Convert into string for logging. String() string } diff --git a/pkg/streaming/util/message/message_id_test.go b/pkg/streaming/util/message/message_id_test.go index 038f2fffc4..84ba67bfdc 100644 --- a/pkg/streaming/util/message/message_id_test.go +++ b/pkg/streaming/util/message/message_id_test.go @@ -6,6 +6,7 @@ import ( "github.com/cockroachdb/errors" "github.com/stretchr/testify/assert" + "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" "github.com/milvus-io/milvus/pkg/v2/mocks/streaming/util/mock_message" "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" ) @@ -13,27 +14,20 @@ import ( func TestRegisterMessageIDUnmarshaler(t *testing.T) { msgID := mock_message.NewMockMessageID(t) - message.RegisterMessageIDUnmsarshaler("test", func(b string) (message.MessageID, error) { - if b == "123" { - return msgID, nil - } - return nil, errors.New("invalid") - }) - - id, err := message.UnmarshalMessageID("test", "123") + id, err := message.UnmarshalMessageID(&commonpb.MessageID{WALName: commonpb.WALName(message.WALNameTest), Id: "123"}) assert.NotNil(t, id) assert.NoError(t, err) - id, err = message.UnmarshalMessageID("test", "1234") + id, err = message.UnmarshalMessageID(&commonpb.MessageID{WALName: commonpb.WALName(message.WALNameTest), Id: "123a"}) assert.Nil(t, id) assert.Error(t, err) assert.Panics(t, func() { - message.UnmarshalMessageID("test1", "123") + message.UnmarshalMessageID(&commonpb.MessageID{WALName: commonpb.WALName(101), Id: "123"}) }) assert.Panics(t, func() { - message.RegisterMessageIDUnmsarshaler("test", func(b string) (message.MessageID, error) { + message.RegisterMessageIDUnmsarshaler(message.WALNameTest, func(b string) (message.MessageID, error) { if b == "123" { return msgID, nil } @@ -44,7 +38,9 @@ func TestRegisterMessageIDUnmarshaler(t *testing.T) { func TestCases(t *testing.T) { msgID := mock_message.NewMockMessageID(t) + msgID.EXPECT().IntoProto().Return(&commonpb.MessageID{WALName: commonpb.WALName(message.WALNameTest), Id: "123"}).Maybe() msgID.EXPECT().Marshal().Return("123").Maybe() + msgID.EXPECT().WALName().Return(message.WALNameTest).Maybe() message.CreateTestInsertMessage(t, 1, 100, 100, msgID) message.CreateTestCreateCollectionMessage(t, 1, 100, msgID) message.CreateTestEmptyInsertMesage(1, nil) diff --git a/pkg/streaming/util/message/message_impl.go b/pkg/streaming/util/message/message_impl.go index 3504ede35c..f67bb2e468 100644 --- a/pkg/streaming/util/message/message_impl.go +++ b/pkg/streaming/util/message/message_impl.go @@ -3,6 +3,7 @@ package message import ( "fmt" + "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" "github.com/milvus-io/milvus/pkg/v2/proto/messagespb" ) @@ -154,6 +155,30 @@ func (m *messageImpl) WithBroadcastID(id uint64) BroadcastMutableMessage { return m } +// OverwriteReplicateVChannel overwrites the vchannel of the replicate message. +func (m *messageImpl) OverwriteReplicateVChannel(vchannel string, broadcastVChannels ...[]string) { + if !m.properties.Exist(messageVChannel) { + panic("vchannel not set in properties of message") + } + m.properties.Set(messageVChannel, vchannel) + if !m.properties.Exist(messageBroadcastHeader) { + return + } + if len(broadcastVChannels) == 0 { + panic("broadcast vchannels not set when overwrite replicate vchannel") + } + bh := m.broadcastHeader() + if len(bh.Vchannels) != len(broadcastVChannels[0]) { + panic("broadcast vchannels length mismatch") + } + bh.Vchannels = broadcastVChannels[0] + bhVal, err := EncodeProto(bh) + if err != nil { + panic("should not happen on broadcast header proto") + } + m.properties.Set(messageBroadcastHeader, bhVal) +} + // IntoImmutableMessage converts current message to immutable message. func (m *messageImpl) IntoImmutableMessage(id MessageID) ImmutableMessage { // payload and id is always immutable, so we only clone the prop here is ok. @@ -221,6 +246,28 @@ func (m *messageImpl) VChannel() string { return value } +// ReplicateHeader returns the replicate header of current message. +// If the replicate header is set, it is a replicated message. +func (m *messageImpl) ReplicateHeader() *ReplicateHeader { + value, ok := m.properties.Get(messageReplicateMesssageHeader) + if !ok { + return nil + } + header := &messagespb.ReplicateHeader{} + if err := DecodeProto(value, header); err != nil { + panic("can not decode replicate header") + } + messageID := MustUnmarshalMessageID(header.MessageId) + lastConfirmedMessageID := MustUnmarshalMessageID(header.LastConfirmedMessageId) + return &ReplicateHeader{ + ClusterID: header.ClusterId, + MessageID: messageID, + LastConfirmedMessageID: lastConfirmedMessageID, + TimeTick: header.TimeTick, + VChannel: header.Vchannel, + } +} + // BroadcastHeader returns the broadcast header of current message. func (m *messageImpl) BroadcastHeader() *BroadcastHeader { header := m.broadcastHeader() @@ -311,7 +358,7 @@ type immutableMessageImpl struct { } // WALName returns the name of message related wal. -func (m *immutableMessageImpl) WALName() string { +func (m *immutableMessageImpl) WALName() WALName { return m.id.WALName() } @@ -329,7 +376,10 @@ func (m *immutableMessageImpl) LastConfirmedMessageID() MessageID { if !ok { panic(fmt.Sprintf("there's a bug in the message codes, last confirmed message lost in properties of message, id: %+v", m.id)) } - id, err := UnmarshalMessageID(m.id.WALName(), value) + id, err := UnmarshalMessageID(&commonpb.MessageID{ + WALName: commonpb.WALName(m.id.WALName()), + Id: value, + }) if err != nil { panic(fmt.Sprintf("there's a bug in the message codes, dirty last confirmed message in properties of message, id: %+v", m.id)) } @@ -370,11 +420,9 @@ func (m *immutableMessageImpl) overwriteLastConfirmedMessageID(id MessageID) { } // IntoImmutableMessageProto converts the message to a protobuf immutable message. -func (m *immutableMessageImpl) IntoImmutableMessageProto() *messagespb.ImmutableMessage { - return &messagespb.ImmutableMessage{ - Id: &messagespb.MessageID{ - Id: m.id.Marshal(), - }, +func (m *immutableMessageImpl) IntoImmutableMessageProto() *commonpb.ImmutableMessage { + return &commonpb.ImmutableMessage{ + Id: m.id.IntoProto(), Payload: m.payload, Properties: m.properties.ToRawMap(), } diff --git a/pkg/streaming/util/message/message_test.go b/pkg/streaming/util/message/message_test.go index efc548a62c..04f375a8b3 100644 --- a/pkg/streaming/util/message/message_test.go +++ b/pkg/streaming/util/message/message_test.go @@ -41,6 +41,22 @@ func TestMessageType(t *testing.T) { assert.False(t, MessageTypeDropCollection.IsSystem()) assert.False(t, MessageTypeCreatePartition.IsSystem()) assert.False(t, MessageTypeDropPartition.IsSystem()) + + assert.True(t, MessageTypeTimeTick.IsSelfControlled()) + assert.False(t, MessageTypeTxn.IsSelfControlled()) + assert.False(t, MessageTypeBeginTxn.IsSelfControlled()) + assert.False(t, MessageTypeCommitTxn.IsSelfControlled()) + assert.False(t, MessageTypeRollbackTxn.IsSelfControlled()) + assert.False(t, MessageTypeImport.IsSelfControlled()) + assert.False(t, MessageTypeInsert.IsSelfControlled()) + assert.False(t, MessageTypeDelete.IsSelfControlled()) + assert.True(t, MessageTypeCreateSegment.IsSelfControlled()) + assert.True(t, MessageTypeFlush.IsSelfControlled()) + assert.False(t, MessageTypeManualFlush.IsSelfControlled()) + assert.False(t, MessageTypeCreateCollection.IsSelfControlled()) + assert.False(t, MessageTypeDropCollection.IsSelfControlled()) + assert.False(t, MessageTypeCreatePartition.IsSelfControlled()) + assert.False(t, MessageTypeDropPartition.IsSelfControlled()) } func TestVersion(t *testing.T) { @@ -126,3 +142,6 @@ func TestCheckIfMessageFromStreaming(t *testing.T) { messageVersion: "1", })) } + +func TestReplicateHeader(t *testing.T) { +} diff --git a/pkg/streaming/util/message/message_type.go b/pkg/streaming/util/message/message_type.go index b15891c39a..33660b3df2 100644 --- a/pkg/streaming/util/message/message_type.go +++ b/pkg/streaming/util/message/message_type.go @@ -45,6 +45,12 @@ func (t MessageType) IsSystem() bool { return ok } +// IsSelfControlled checks if the MessageType is self controlled. +func (t MessageType) IsSelfControlled() bool { + _, ok := selfControlledMessageType[t] + return ok +} + // unmarshalMessageType unmarshal MessageType from string. func unmarshalMessageType(s string) MessageType { i, err := strconv.ParseInt(s, 10, 32) diff --git a/pkg/streaming/util/message/properties.go b/pkg/streaming/util/message/properties.go index bb3c9e98cf..55c0311b34 100644 --- a/pkg/streaming/util/message/properties.go +++ b/pkg/streaming/util/message/properties.go @@ -15,6 +15,7 @@ const ( messageTxnContext = "_tx" // transaction context. messageCipherHeader = "_ch" // message cipher header. messageNotPersisteted = "_np" // check if the message is unpersisted. + messageReplicateMesssageHeader = "_rh" // replicate message header. ) var ( diff --git a/pkg/streaming/util/message/reflect_info.go b/pkg/streaming/util/message/reflect_info.go index 7cf893e19c..29c91cfe2a 100644 --- a/pkg/streaming/util/message/reflect_info.go +++ b/pkg/streaming/util/message/reflect_info.go @@ -12,23 +12,24 @@ import ( // Export message types const ( - MessageTypeUnknown MessageType = MessageType(messagespb.MessageType_Unknown) - MessageTypeTimeTick MessageType = MessageType(messagespb.MessageType_TimeTick) - MessageTypeInsert MessageType = MessageType(messagespb.MessageType_Insert) - MessageTypeDelete MessageType = MessageType(messagespb.MessageType_Delete) - MessageTypeCreateCollection MessageType = MessageType(messagespb.MessageType_CreateCollection) - MessageTypeDropCollection MessageType = MessageType(messagespb.MessageType_DropCollection) - MessageTypeCreatePartition MessageType = MessageType(messagespb.MessageType_CreatePartition) - MessageTypeDropPartition MessageType = MessageType(messagespb.MessageType_DropPartition) - MessageTypeImport MessageType = MessageType(messagespb.MessageType_Import) - MessageTypeCreateSegment MessageType = MessageType(messagespb.MessageType_CreateSegment) - MessageTypeFlush MessageType = MessageType(messagespb.MessageType_Flush) - MessageTypeManualFlush MessageType = MessageType(messagespb.MessageType_ManualFlush) - MessageTypeBeginTxn MessageType = MessageType(messagespb.MessageType_BeginTxn) - MessageTypeCommitTxn MessageType = MessageType(messagespb.MessageType_CommitTxn) - MessageTypeRollbackTxn MessageType = MessageType(messagespb.MessageType_RollbackTxn) - MessageTypeTxn MessageType = MessageType(messagespb.MessageType_Txn) - MessageTypeSchemaChange MessageType = MessageType(messagespb.MessageType_SchemaChange) + MessageTypeUnknown MessageType = MessageType(messagespb.MessageType_Unknown) + MessageTypeTimeTick MessageType = MessageType(messagespb.MessageType_TimeTick) + MessageTypeInsert MessageType = MessageType(messagespb.MessageType_Insert) + MessageTypeDelete MessageType = MessageType(messagespb.MessageType_Delete) + MessageTypeCreateCollection MessageType = MessageType(messagespb.MessageType_CreateCollection) + MessageTypeDropCollection MessageType = MessageType(messagespb.MessageType_DropCollection) + MessageTypeCreatePartition MessageType = MessageType(messagespb.MessageType_CreatePartition) + MessageTypeDropPartition MessageType = MessageType(messagespb.MessageType_DropPartition) + MessageTypeImport MessageType = MessageType(messagespb.MessageType_Import) + MessageTypeCreateSegment MessageType = MessageType(messagespb.MessageType_CreateSegment) + MessageTypeFlush MessageType = MessageType(messagespb.MessageType_Flush) + MessageTypeManualFlush MessageType = MessageType(messagespb.MessageType_ManualFlush) + MessageTypePutReplicateConfig MessageType = MessageType(messagespb.MessageType_PutReplicateConfig) + MessageTypeBeginTxn MessageType = MessageType(messagespb.MessageType_BeginTxn) + MessageTypeCommitTxn MessageType = MessageType(messagespb.MessageType_CommitTxn) + MessageTypeRollbackTxn MessageType = MessageType(messagespb.MessageType_RollbackTxn) + MessageTypeTxn MessageType = MessageType(messagespb.MessageType_Txn) + MessageTypeSchemaChange MessageType = MessageType(messagespb.MessageType_SchemaChange) ) // Export extra message type @@ -40,38 +41,40 @@ type ( // Export message header and body types type ( - TimeTickMessageHeader = messagespb.TimeTickMessageHeader - TimeTickMsg = msgpb.TimeTickMsg - InsertMessageHeader = messagespb.InsertMessageHeader - InsertRequest = msgpb.InsertRequest - DeleteMessageHeader = messagespb.DeleteMessageHeader - DeleteRequest = msgpb.DeleteRequest - CreateCollectionMessageHeader = messagespb.CreateCollectionMessageHeader - CreateCollectionRequest = msgpb.CreateCollectionRequest - DropCollectionMessageHeader = messagespb.DropCollectionMessageHeader - DropCollectionRequest = msgpb.DropCollectionRequest - CreatePartitionMessageHeader = messagespb.CreatePartitionMessageHeader - CreatePartitionRequest = msgpb.CreatePartitionRequest - DropPartitionMessageHeader = messagespb.DropPartitionMessageHeader - DropPartitionRequest = msgpb.DropPartitionRequest - ImportMessageHeader = messagespb.ImportMessageHeader - ImportMsg = msgpb.ImportMsg - CreateSegmentMessageHeader = messagespb.CreateSegmentMessageHeader - CreateSegmentMessageBody = messagespb.CreateSegmentMessageBody - FlushMessageHeader = messagespb.FlushMessageHeader - FlushMessageBody = messagespb.FlushMessageBody - ManualFlushMessageHeader = messagespb.ManualFlushMessageHeader - ManualFlushMessageBody = messagespb.ManualFlushMessageBody - BeginTxnMessageHeader = messagespb.BeginTxnMessageHeader - BeginTxnMessageBody = messagespb.BeginTxnMessageBody - CommitTxnMessageHeader = messagespb.CommitTxnMessageHeader - CommitTxnMessageBody = messagespb.CommitTxnMessageBody - RollbackTxnMessageHeader = messagespb.RollbackTxnMessageHeader - RollbackTxnMessageBody = messagespb.RollbackTxnMessageBody - TxnMessageHeader = messagespb.TxnMessageHeader - TxnMessageBody = messagespb.TxnMessageBody - SchemaChangeMessageHeader = messagespb.SchemaChangeMessageHeader - SchemaChangeMessageBody = messagespb.SchemaChangeMessageBody + TimeTickMessageHeader = messagespb.TimeTickMessageHeader + TimeTickMsg = msgpb.TimeTickMsg + InsertMessageHeader = messagespb.InsertMessageHeader + InsertRequest = msgpb.InsertRequest + DeleteMessageHeader = messagespb.DeleteMessageHeader + DeleteRequest = msgpb.DeleteRequest + CreateCollectionMessageHeader = messagespb.CreateCollectionMessageHeader + CreateCollectionRequest = msgpb.CreateCollectionRequest + DropCollectionMessageHeader = messagespb.DropCollectionMessageHeader + DropCollectionRequest = msgpb.DropCollectionRequest + CreatePartitionMessageHeader = messagespb.CreatePartitionMessageHeader + CreatePartitionRequest = msgpb.CreatePartitionRequest + DropPartitionMessageHeader = messagespb.DropPartitionMessageHeader + DropPartitionRequest = msgpb.DropPartitionRequest + ImportMessageHeader = messagespb.ImportMessageHeader + ImportMsg = msgpb.ImportMsg + CreateSegmentMessageHeader = messagespb.CreateSegmentMessageHeader + CreateSegmentMessageBody = messagespb.CreateSegmentMessageBody + FlushMessageHeader = messagespb.FlushMessageHeader + FlushMessageBody = messagespb.FlushMessageBody + ManualFlushMessageHeader = messagespb.ManualFlushMessageHeader + ManualFlushMessageBody = messagespb.ManualFlushMessageBody + PutReplicateConfigMessageHeader = messagespb.PutReplicateConfigMessageHeader + PutReplicateConfigMessageBody = messagespb.PutReplicateConfigMessageBody + BeginTxnMessageHeader = messagespb.BeginTxnMessageHeader + BeginTxnMessageBody = messagespb.BeginTxnMessageBody + CommitTxnMessageHeader = messagespb.CommitTxnMessageHeader + CommitTxnMessageBody = messagespb.CommitTxnMessageBody + RollbackTxnMessageHeader = messagespb.RollbackTxnMessageHeader + RollbackTxnMessageBody = messagespb.RollbackTxnMessageBody + TxnMessageHeader = messagespb.TxnMessageHeader + TxnMessageBody = messagespb.TxnMessageBody + SchemaChangeMessageHeader = messagespb.SchemaChangeMessageHeader + SchemaChangeMessageBody = messagespb.SchemaChangeMessageBody ) // Type aliases for TimeTickMessageV1 @@ -514,6 +517,46 @@ var MustAsBroadcastManualFlushMessageV2 = MustAsSpecializedBroadcastMessage[*Man // NewManualFlushMessageBuilderV2 creates a new message builder for ManualFlushMessageV2 var NewManualFlushMessageBuilderV2 = newMutableMessageBuilder[*ManualFlushMessageHeader, *ManualFlushMessageBody] +// Type aliases for PutReplicateConfigMessageV2 +type ( + MutablePutReplicateConfigMessageV2 = specializedMutableMessage[*PutReplicateConfigMessageHeader, *PutReplicateConfigMessageBody] + ImmutablePutReplicateConfigMessageV2 = SpecializedImmutableMessage[*PutReplicateConfigMessageHeader, *PutReplicateConfigMessageBody] + BroadcastPutReplicateConfigMessageV2 = SpecializedBroadcastMessage[*PutReplicateConfigMessageHeader, *PutReplicateConfigMessageBody] +) + +// MessageTypeWithVersion for PutReplicateConfigMessageV2 +var MessageTypePutReplicateConfigV2 = MessageTypeWithVersion{ + MessageType: MessageTypePutReplicateConfig, + Version: VersionV2, +} + +// MessageSpecializedType for PutReplicateConfigMessageV2 +var SpecializedTypePutReplicateConfigV2 = MessageSpecializedType{ + BodyType: reflect.TypeOf((*PutReplicateConfigMessageBody)(nil)), + HeaderType: reflect.TypeOf((*PutReplicateConfigMessageHeader)(nil)), +} + +// AsMutablePutReplicateConfigMessageV2 converts a BasicMessage to MutablePutReplicateConfigMessageV2 +var AsMutablePutReplicateConfigMessageV2 = asSpecializedMutableMessage[*PutReplicateConfigMessageHeader, *PutReplicateConfigMessageBody] + +// MustAsMutablePutReplicateConfigMessageV2 converts a BasicMessage to MutablePutReplicateConfigMessageV2, panics on error +var MustAsMutablePutReplicateConfigMessageV2 = mustAsSpecializedMutableMessage[*PutReplicateConfigMessageHeader, *PutReplicateConfigMessageBody] + +// AsImmutablePutReplicateConfigMessageV2 converts an ImmutableMessage to ImmutablePutReplicateConfigMessageV2 +var AsImmutablePutReplicateConfigMessageV2 = asSpecializedImmutableMessage[*PutReplicateConfigMessageHeader, *PutReplicateConfigMessageBody] + +// MustAsImmutablePutReplicateConfigMessageV2 converts an ImmutableMessage to ImmutablePutReplicateConfigMessageV2, panics on error +var MustAsImmutablePutReplicateConfigMessageV2 = MustAsSpecializedImmutableMessage[*PutReplicateConfigMessageHeader, *PutReplicateConfigMessageBody] + +// AsBroadcastPutReplicateConfigMessageV2 converts a BasicMessage to BroadcastPutReplicateConfigMessageV2 +var AsBroadcastPutReplicateConfigMessageV2 = asSpecializedBroadcastMessage[*PutReplicateConfigMessageHeader, *PutReplicateConfigMessageBody] + +// MustAsBroadcastPutReplicateConfigMessageV2 converts a BasicMessage to BroadcastPutReplicateConfigMessageV2, panics on error +var MustAsBroadcastPutReplicateConfigMessageV2 = MustAsSpecializedBroadcastMessage[*PutReplicateConfigMessageHeader, *PutReplicateConfigMessageBody] + +// NewPutReplicateConfigMessageBuilderV2 creates a new message builder for PutReplicateConfigMessageV2 +var NewPutReplicateConfigMessageBuilderV2 = newMutableMessageBuilder[*PutReplicateConfigMessageHeader, *PutReplicateConfigMessageBody] + // Type aliases for BeginTxnMessageV2 type ( MutableBeginTxnMessageV2 = specializedMutableMessage[*BeginTxnMessageHeader, *BeginTxnMessageBody] @@ -695,22 +738,23 @@ var NewSchemaChangeMessageBuilderV2 = newMutableMessageBuilder[*SchemaChangeMess // messageTypeMap make the contriants that one header type can only be used for one message type. var messageTypeMap = map[reflect.Type]MessageType{ - reflect.TypeOf(&messagespb.BeginTxnMessageHeader{}): MessageTypeBeginTxn, - reflect.TypeOf(&messagespb.CommitTxnMessageHeader{}): MessageTypeCommitTxn, - reflect.TypeOf(&messagespb.CreateCollectionMessageHeader{}): MessageTypeCreateCollection, - reflect.TypeOf(&messagespb.CreatePartitionMessageHeader{}): MessageTypeCreatePartition, - reflect.TypeOf(&messagespb.CreateSegmentMessageHeader{}): MessageTypeCreateSegment, - reflect.TypeOf(&messagespb.DeleteMessageHeader{}): MessageTypeDelete, - reflect.TypeOf(&messagespb.DropCollectionMessageHeader{}): MessageTypeDropCollection, - reflect.TypeOf(&messagespb.DropPartitionMessageHeader{}): MessageTypeDropPartition, - reflect.TypeOf(&messagespb.FlushMessageHeader{}): MessageTypeFlush, - reflect.TypeOf(&messagespb.ImportMessageHeader{}): MessageTypeImport, - reflect.TypeOf(&messagespb.InsertMessageHeader{}): MessageTypeInsert, - reflect.TypeOf(&messagespb.ManualFlushMessageHeader{}): MessageTypeManualFlush, - reflect.TypeOf(&messagespb.RollbackTxnMessageHeader{}): MessageTypeRollbackTxn, - reflect.TypeOf(&messagespb.SchemaChangeMessageHeader{}): MessageTypeSchemaChange, - reflect.TypeOf(&messagespb.TimeTickMessageHeader{}): MessageTypeTimeTick, - reflect.TypeOf(&messagespb.TxnMessageHeader{}): MessageTypeTxn, + reflect.TypeOf(&messagespb.BeginTxnMessageHeader{}): MessageTypeBeginTxn, + reflect.TypeOf(&messagespb.CommitTxnMessageHeader{}): MessageTypeCommitTxn, + reflect.TypeOf(&messagespb.CreateCollectionMessageHeader{}): MessageTypeCreateCollection, + reflect.TypeOf(&messagespb.CreatePartitionMessageHeader{}): MessageTypeCreatePartition, + reflect.TypeOf(&messagespb.CreateSegmentMessageHeader{}): MessageTypeCreateSegment, + reflect.TypeOf(&messagespb.DeleteMessageHeader{}): MessageTypeDelete, + reflect.TypeOf(&messagespb.DropCollectionMessageHeader{}): MessageTypeDropCollection, + reflect.TypeOf(&messagespb.DropPartitionMessageHeader{}): MessageTypeDropPartition, + reflect.TypeOf(&messagespb.FlushMessageHeader{}): MessageTypeFlush, + reflect.TypeOf(&messagespb.ImportMessageHeader{}): MessageTypeImport, + reflect.TypeOf(&messagespb.InsertMessageHeader{}): MessageTypeInsert, + reflect.TypeOf(&messagespb.ManualFlushMessageHeader{}): MessageTypeManualFlush, + reflect.TypeOf(&messagespb.PutReplicateConfigMessageHeader{}): MessageTypePutReplicateConfig, + reflect.TypeOf(&messagespb.RollbackTxnMessageHeader{}): MessageTypeRollbackTxn, + reflect.TypeOf(&messagespb.SchemaChangeMessageHeader{}): MessageTypeSchemaChange, + reflect.TypeOf(&messagespb.TimeTickMessageHeader{}): MessageTypeTimeTick, + reflect.TypeOf(&messagespb.TxnMessageHeader{}): MessageTypeTxn, } // MessageTypeWithVersion identifies a message type and version @@ -731,40 +775,42 @@ type MessageSpecializedType struct { // messageTypeVersionSpecializedMap maps MessageTypeWithVersion to MessageSpecializedType var messageTypeVersionSpecializedMap = map[MessageTypeWithVersion]MessageSpecializedType{ - MessageTypeBeginTxnV2: SpecializedTypeBeginTxnV2, - MessageTypeCommitTxnV2: SpecializedTypeCommitTxnV2, - MessageTypeCreateCollectionV1: SpecializedTypeCreateCollectionV1, - MessageTypeCreatePartitionV1: SpecializedTypeCreatePartitionV1, - MessageTypeCreateSegmentV2: SpecializedTypeCreateSegmentV2, - MessageTypeDeleteV1: SpecializedTypeDeleteV1, - MessageTypeDropCollectionV1: SpecializedTypeDropCollectionV1, - MessageTypeDropPartitionV1: SpecializedTypeDropPartitionV1, - MessageTypeFlushV2: SpecializedTypeFlushV2, - MessageTypeImportV1: SpecializedTypeImportV1, - MessageTypeInsertV1: SpecializedTypeInsertV1, - MessageTypeManualFlushV2: SpecializedTypeManualFlushV2, - MessageTypeRollbackTxnV2: SpecializedTypeRollbackTxnV2, - MessageTypeSchemaChangeV2: SpecializedTypeSchemaChangeV2, - MessageTypeTimeTickV1: SpecializedTypeTimeTickV1, - MessageTypeTxnV2: SpecializedTypeTxnV2, + MessageTypeBeginTxnV2: SpecializedTypeBeginTxnV2, + MessageTypeCommitTxnV2: SpecializedTypeCommitTxnV2, + MessageTypeCreateCollectionV1: SpecializedTypeCreateCollectionV1, + MessageTypeCreatePartitionV1: SpecializedTypeCreatePartitionV1, + MessageTypeCreateSegmentV2: SpecializedTypeCreateSegmentV2, + MessageTypeDeleteV1: SpecializedTypeDeleteV1, + MessageTypeDropCollectionV1: SpecializedTypeDropCollectionV1, + MessageTypeDropPartitionV1: SpecializedTypeDropPartitionV1, + MessageTypeFlushV2: SpecializedTypeFlushV2, + MessageTypeImportV1: SpecializedTypeImportV1, + MessageTypeInsertV1: SpecializedTypeInsertV1, + MessageTypeManualFlushV2: SpecializedTypeManualFlushV2, + MessageTypePutReplicateConfigV2: SpecializedTypePutReplicateConfigV2, + MessageTypeRollbackTxnV2: SpecializedTypeRollbackTxnV2, + MessageTypeSchemaChangeV2: SpecializedTypeSchemaChangeV2, + MessageTypeTimeTickV1: SpecializedTypeTimeTickV1, + MessageTypeTxnV2: SpecializedTypeTxnV2, } // messageSpecializedTypeVersionMap maps MessageSpecializedType to MessageTypeWithVersion var messageSpecializedTypeVersionMap = map[MessageSpecializedType]MessageTypeWithVersion{ - SpecializedTypeBeginTxnV2: MessageTypeBeginTxnV2, - SpecializedTypeCommitTxnV2: MessageTypeCommitTxnV2, - SpecializedTypeCreateCollectionV1: MessageTypeCreateCollectionV1, - SpecializedTypeCreatePartitionV1: MessageTypeCreatePartitionV1, - SpecializedTypeCreateSegmentV2: MessageTypeCreateSegmentV2, - SpecializedTypeDeleteV1: MessageTypeDeleteV1, - SpecializedTypeDropCollectionV1: MessageTypeDropCollectionV1, - SpecializedTypeDropPartitionV1: MessageTypeDropPartitionV1, - SpecializedTypeFlushV2: MessageTypeFlushV2, - SpecializedTypeImportV1: MessageTypeImportV1, - SpecializedTypeInsertV1: MessageTypeInsertV1, - SpecializedTypeManualFlushV2: MessageTypeManualFlushV2, - SpecializedTypeRollbackTxnV2: MessageTypeRollbackTxnV2, - SpecializedTypeSchemaChangeV2: MessageTypeSchemaChangeV2, - SpecializedTypeTimeTickV1: MessageTypeTimeTickV1, - SpecializedTypeTxnV2: MessageTypeTxnV2, + SpecializedTypeBeginTxnV2: MessageTypeBeginTxnV2, + SpecializedTypeCommitTxnV2: MessageTypeCommitTxnV2, + SpecializedTypeCreateCollectionV1: MessageTypeCreateCollectionV1, + SpecializedTypeCreatePartitionV1: MessageTypeCreatePartitionV1, + SpecializedTypeCreateSegmentV2: MessageTypeCreateSegmentV2, + SpecializedTypeDeleteV1: MessageTypeDeleteV1, + SpecializedTypeDropCollectionV1: MessageTypeDropCollectionV1, + SpecializedTypeDropPartitionV1: MessageTypeDropPartitionV1, + SpecializedTypeFlushV2: MessageTypeFlushV2, + SpecializedTypeImportV1: MessageTypeImportV1, + SpecializedTypeInsertV1: MessageTypeInsertV1, + SpecializedTypeManualFlushV2: MessageTypeManualFlushV2, + SpecializedTypePutReplicateConfigV2: MessageTypePutReplicateConfigV2, + SpecializedTypeRollbackTxnV2: MessageTypeRollbackTxnV2, + SpecializedTypeSchemaChangeV2: MessageTypeSchemaChangeV2, + SpecializedTypeTimeTickV1: MessageTypeTimeTickV1, + SpecializedTypeTxnV2: MessageTypeTxnV2, } diff --git a/pkg/streaming/util/message/specialized_message.go b/pkg/streaming/util/message/specialized_message.go index 879041b67e..ad86daecac 100644 --- a/pkg/streaming/util/message/specialized_message.go +++ b/pkg/streaming/util/message/specialized_message.go @@ -17,18 +17,25 @@ var systemMessageType = map[MessageType]struct{}{ MessageTypeTxn: {}, } +var selfControlledMessageType = map[MessageType]struct{}{ + MessageTypeTimeTick: {}, + MessageTypeCreateSegment: {}, + MessageTypeFlush: {}, +} + var cipherMessageType = map[MessageType]struct{}{ MessageTypeInsert: {}, MessageTypeDelete: {}, } var exclusiveRequiredMessageType = map[MessageType]struct{}{ - MessageTypeCreateCollection: {}, - MessageTypeDropCollection: {}, - MessageTypeCreatePartition: {}, - MessageTypeDropPartition: {}, - MessageTypeManualFlush: {}, - MessageTypeSchemaChange: {}, + MessageTypeCreateCollection: {}, + MessageTypeDropCollection: {}, + MessageTypeCreatePartition: {}, + MessageTypeDropPartition: {}, + MessageTypeManualFlush: {}, + MessageTypeSchemaChange: {}, + MessageTypePutReplicateConfig: {}, } // mustAsSpecializedMutableMessage converts a MutableMessage to a specialized MutableMessage. @@ -203,6 +210,15 @@ func (m *specializedMutableMessageImpl[H, B]) OverwriteHeader(header H) { m.messageImpl.properties.Set(messageHeader, newHeader) } +// OverwriteBody overwrites the message body. +func (m *specializedMutableMessageImpl[H, B]) OverwriteBody(body B) { + payload, err := proto.Marshal(body) + if err != nil { + panic(fmt.Sprintf("failed to marshal specialized body, %s", err.Error())) + } + m.messageImpl.payload = payload +} + // specializedImmutableMessageImpl is the specialized immmutable message implementation. type specializedImmutableMessageImpl[H proto.Message, B proto.Message] struct { header H diff --git a/pkg/streaming/util/message/utils.go b/pkg/streaming/util/message/utils.go index e219658bd1..73d33f69e9 100644 --- a/pkg/streaming/util/message/utils.go +++ b/pkg/streaming/util/message/utils.go @@ -51,3 +51,12 @@ func MustGetMessageTypeWithVersion[H proto.Message, B proto.Message]() MessageTy } return mv } + +// ReplicateHeader is the header of replicate message. +type ReplicateHeader struct { + ClusterID string + MessageID MessageID + LastConfirmedMessageID MessageID + TimeTick uint64 + VChannel string +} diff --git a/pkg/streaming/util/message/wal_name.go b/pkg/streaming/util/message/wal_name.go new file mode 100644 index 0000000000..e8643458cc --- /dev/null +++ b/pkg/streaming/util/message/wal_name.go @@ -0,0 +1,55 @@ +package message + +import ( + "go.uber.org/atomic" + + "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" +) + +type WALName commonpb.WALName + +const ( + WALNameUnknown WALName = WALName(commonpb.WALName_Unknown) + WALNameRocksmq WALName = WALName(commonpb.WALName_RocksMQ) + WALNameKafka WALName = WALName(commonpb.WALName_Kafka) + WALNamePulsar WALName = WALName(commonpb.WALName_Pulsar) + WALNameWoodpecker WALName = WALName(commonpb.WALName_WoodPecker) + WALNameTest WALName = WALName(commonpb.WALName_Test) +) + +var defaultWALName = atomic.NewPointer[WALName](nil) + +// RegisterDefaultWALName register the default WALName. +func RegisterDefaultWALName(walName WALName) { + defaultWALName.Store(&walName) +} + +// MustGetDefaultWALName get the default WALName. +func MustGetDefaultWALName() WALName { + return *defaultWALName.Load() +} + +// NewWALName create a WALName from string. +func NewWALName(name string) WALName { + for wal, n := range walNameMap { + if n == name { + return wal + } + } + return WALNameUnknown +} + +// walNameMap is the mapping from WALName to string. +var walNameMap = map[WALName]string{ + WALNameUnknown: "unknown", + WALNameRocksmq: "rocksmq", + WALNameKafka: "kafka", + WALNamePulsar: "pulsar", + WALNameWoodpecker: "woodpecker", + WALNameTest: "walimplstest", +} + +// String returns the string representation of the WALName. +func (w WALName) String() string { + return walNameMap[w] +} diff --git a/pkg/streaming/util/options/deliver.go b/pkg/streaming/util/options/deliver.go index d5f1aea092..5782a160ea 100644 --- a/pkg/streaming/util/options/deliver.go +++ b/pkg/streaming/util/options/deliver.go @@ -44,9 +44,7 @@ func DeliverPolicyLatest() DeliverPolicy { func DeliverPolicyStartFrom(messageID message.MessageID) DeliverPolicy { return &streamingpb.DeliverPolicy{ Policy: &streamingpb.DeliverPolicy_StartFrom{ - StartFrom: &messagespb.MessageID{ - Id: messageID.Marshal(), - }, + StartFrom: messageID.IntoProto(), }, } } @@ -55,9 +53,7 @@ func DeliverPolicyStartFrom(messageID message.MessageID) DeliverPolicy { func DeliverPolicyStartAfter(messageID message.MessageID) DeliverPolicy { return &streamingpb.DeliverPolicy{ Policy: &streamingpb.DeliverPolicy_StartAfter{ - StartAfter: &messagespb.MessageID{ - Id: messageID.Marshal(), - }, + StartAfter: messageID.IntoProto(), }, } } diff --git a/pkg/streaming/util/options/deliver_test.go b/pkg/streaming/util/options/deliver_test.go index 11ab627210..bff4376dd7 100644 --- a/pkg/streaming/util/options/deliver_test.go +++ b/pkg/streaming/util/options/deliver_test.go @@ -5,6 +5,7 @@ import ( "github.com/stretchr/testify/assert" + "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" "github.com/milvus-io/milvus/pkg/v2/mocks/streaming/util/mock_message" "github.com/milvus-io/milvus/pkg/v2/proto/streamingpb" "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" @@ -18,7 +19,7 @@ func TestDeliverPolicy(t *testing.T) { _ = policy.GetPolicy().(*streamingpb.DeliverPolicy_Latest) messageID := mock_message.NewMockMessageID(t) - messageID.EXPECT().Marshal().Return("messageID") + messageID.EXPECT().IntoProto().Return(&commonpb.MessageID{WALName: commonpb.WALName(message.WALNameTest), Id: "123"}) policy = DeliverPolicyStartFrom(messageID) _ = policy.GetPolicy().(*streamingpb.DeliverPolicy_StartFrom) diff --git a/pkg/streaming/util/types/acked_result.go b/pkg/streaming/util/types/acked_result.go new file mode 100644 index 0000000000..0cc37ae542 --- /dev/null +++ b/pkg/streaming/util/types/acked_result.go @@ -0,0 +1,68 @@ +package types + +import ( + "github.com/milvus-io/milvus/pkg/v2/proto/streamingpb" + "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" +) + +// NewAckedPendings creates a new AckedPendings. +func NewAckedPendings(channels []string) *AckedResult { + return &AckedResult{ + AckedResult: &streamingpb.AckedResult{ + Channels: channels, + AckedCheckpoints: make([]*streamingpb.AckedCheckpoint, len(channels)), + }, + } +} + +// NewAckedPendingsFromProto creates a new AckedPendings from proto. +func NewAckedPendingsFromProto(pendings *streamingpb.AckedResult) *AckedResult { + if pendings == nil { + return nil + } + return &AckedResult{ + AckedResult: pendings, + } +} + +// AckedResult is the pendings of the ack. +type AckedResult struct { + *streamingpb.AckedResult +} + +type AckedCheckpoint struct { + Channel string + MessageID message.MessageID + LastConfirmedMessageID message.MessageID + TimeTick uint64 +} + +// Ack marks the item as acked. +// panic if the channel is not found. +// return true if the channel is acked, false if the channel is already acked. +func (a *AckedResult) Ack(cp AckedCheckpoint) bool { + for idx, v := range a.Channels { + if v == cp.Channel { + if a.AckedCheckpoints[idx] == nil { + a.AckedCheckpoints[idx] = &streamingpb.AckedCheckpoint{ + MessageId: cp.MessageID.IntoProto(), + LastConfirmedMessageId: cp.LastConfirmedMessageID.IntoProto(), + TimeTick: cp.TimeTick, + } + return true + } + return false + } + } + panic("channel not found") +} + +// IsAllAcked returns true if all the channels are acked. +func (a *AckedResult) IsAllAcked() bool { + for _, v := range a.AckedCheckpoints { + if v == nil { + return false + } + } + return true +} diff --git a/pkg/streaming/util/types/acked_result_test.go b/pkg/streaming/util/types/acked_result_test.go new file mode 100644 index 0000000000..f9c71c585f --- /dev/null +++ b/pkg/streaming/util/types/acked_result_test.go @@ -0,0 +1,95 @@ +package types_test + +import ( + "testing" + + "github.com/stretchr/testify/suite" + + "github.com/milvus-io/milvus/pkg/v2/proto/streamingpb" + "github.com/milvus-io/milvus/pkg/v2/streaming/util/types" + "github.com/milvus-io/milvus/pkg/v2/streaming/walimpls/impls/walimplstest" +) + +type AckedResultTestSuite struct { + suite.Suite +} + +func TestAckedResult(t *testing.T) { + suite.Run(t, new(AckedResultTestSuite)) +} + +func (s *AckedResultTestSuite) TestNewAckedPendings() { + channels := []string{"ch1", "ch2"} + result := types.NewAckedPendings(channels) + + s.Equal(channels, result.Channels) + s.Equal(len(channels), len(result.AckedCheckpoints)) + for _, cp := range result.AckedCheckpoints { + s.Nil(cp) + } +} + +func (s *AckedResultTestSuite) TestNewAckedPendingsFromProto() { + // Test nil input + s.Nil(types.NewAckedPendingsFromProto(nil)) + + // Test valid input + proto := &streamingpb.AckedResult{ + Channels: []string{"ch1"}, + AckedCheckpoints: []*streamingpb.AckedCheckpoint{nil}, + } + result := types.NewAckedPendingsFromProto(proto) + s.Equal(proto, result.AckedResult) +} + +func (s *AckedResultTestSuite) TestAck() { + channels := []string{"ch1", "ch2"} + result := types.NewAckedPendings(channels) + + // Test successful ack + cp := types.AckedCheckpoint{ + Channel: "ch1", + MessageID: walimplstest.NewTestMessageID(1), + LastConfirmedMessageID: walimplstest.NewTestMessageID(0), + TimeTick: 100, + } + s.True(result.Ack(cp)) + s.NotNil(result.AckedCheckpoints[0]) + s.Equal(cp.MessageID.IntoProto(), result.AckedCheckpoints[0].MessageId) + s.Equal(cp.LastConfirmedMessageID.IntoProto(), result.AckedCheckpoints[0].LastConfirmedMessageId) + s.Equal(cp.TimeTick, result.AckedCheckpoints[0].TimeTick) + + // Test duplicate ack + s.False(result.Ack(cp)) + + // Test panic on non-existent channel + s.Panics(func() { + result.Ack(types.AckedCheckpoint{Channel: "non-existent"}) + }) +} + +func (s *AckedResultTestSuite) TestIsAllAcked() { + channels := []string{"ch1", "ch2"} + result := types.NewAckedPendings(channels) + + // Test not all acked + s.False(result.IsAllAcked()) + + // Ack first channel + result.Ack(types.AckedCheckpoint{ + Channel: "ch1", + MessageID: walimplstest.NewTestMessageID(1), + LastConfirmedMessageID: walimplstest.NewTestMessageID(0), + TimeTick: 100, + }) + s.False(result.IsAllAcked()) + + // Ack second channel + result.Ack(types.AckedCheckpoint{ + Channel: "ch2", + MessageID: walimplstest.NewTestMessageID(2), + LastConfirmedMessageID: walimplstest.NewTestMessageID(1), + TimeTick: 200, + }) + s.True(result.IsAllAcked()) +} diff --git a/pkg/streaming/util/types/responses.go b/pkg/streaming/util/types/responses.go index 7da75fe704..d1a33e81e9 100644 --- a/pkg/streaming/util/types/responses.go +++ b/pkg/streaming/util/types/responses.go @@ -4,7 +4,6 @@ import ( "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" - "github.com/milvus-io/milvus/pkg/v2/proto/messagespb" "github.com/milvus-io/milvus/pkg/v2/proto/streamingpb" "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" ) @@ -48,9 +47,7 @@ func (r *AppendResult) GetExtra(m proto.Message) error { // IntoProto converts the append result to proto. func (r *AppendResult) IntoProto() *streamingpb.ProduceMessageResponseResult { return &streamingpb.ProduceMessageResponseResult{ - Id: &messagespb.MessageID{ - Id: r.MessageID.Marshal(), - }, + Id: r.MessageID.IntoProto(), Timetick: r.TimeTick, TxnContext: r.TxnCtx.IntoProto(), Extra: r.Extra, diff --git a/pkg/streaming/util/types/responses_test.go b/pkg/streaming/util/types/responses_test.go index 91dd9add86..e6698b16c8 100644 --- a/pkg/streaming/util/types/responses_test.go +++ b/pkg/streaming/util/types/responses_test.go @@ -6,6 +6,7 @@ import ( "github.com/stretchr/testify/assert" "google.golang.org/protobuf/types/known/anypb" + "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" "github.com/milvus-io/milvus/pkg/v2/mocks/streaming/util/mock_message" "github.com/milvus-io/milvus/pkg/v2/proto/messagespb" "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" @@ -39,7 +40,7 @@ func TestAppendResult_GetExtra(t *testing.T) { func TestAppendResult_IntoProto(t *testing.T) { msgID := mock_message.NewMockMessageID(t) - msgID.EXPECT().Marshal().Return("1") + msgID.EXPECT().IntoProto().Return(&commonpb.MessageID{WALName: commonpb.WALName(message.WALNameTest), Id: "1"}) result := &AppendResult{ MessageID: msgID, TimeTick: 12345, diff --git a/pkg/streaming/util/types/streaming_node.go b/pkg/streaming/util/types/streaming_node.go index 6ca8d26a72..8e7a35804e 100644 --- a/pkg/streaming/util/types/streaming_node.go +++ b/pkg/streaming/util/types/streaming_node.go @@ -7,6 +7,7 @@ import ( "github.com/cockroachdb/errors" "github.com/milvus-io/milvus/pkg/v2/proto/streamingpb" + "github.com/milvus-io/milvus/pkg/v2/util/replicateutil" "github.com/milvus-io/milvus/pkg/v2/util/typeutil" ) @@ -35,9 +36,10 @@ type AssignmentRebalanceTrigger interface { // VersionedStreamingNodeAssignments is the relation between server and channels with version. type VersionedStreamingNodeAssignments struct { - Version typeutil.VersionInt64Pair - Assignments map[int64]StreamingNodeAssignment - CChannel *streamingpb.CChannelAssignment + Version typeutil.VersionInt64Pair + Assignments map[int64]StreamingNodeAssignment + CChannel *streamingpb.CChannelAssignment + ReplicateConfigHelper *replicateutil.ConfigHelper } // PChannelOfCChannel returns the pchannel of the cchannel. diff --git a/pkg/streaming/walimpls/builder.go b/pkg/streaming/walimpls/builder.go index 4a41a74914..c8390c2eda 100644 --- a/pkg/streaming/walimpls/builder.go +++ b/pkg/streaming/walimpls/builder.go @@ -1,9 +1,11 @@ package walimpls +import "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" + // OpenerBuilderImpls is the interface for building wal opener impls. type OpenerBuilderImpls interface { // Name of the wal builder, should be a lowercase string. - Name() string + Name() message.WALName // Build build a opener impls instance. Build() (OpenerImpls, error) diff --git a/pkg/streaming/walimpls/impls/kafka/builder.go b/pkg/streaming/walimpls/impls/kafka/builder.go index 81119fa4fe..2e04a07788 100644 --- a/pkg/streaming/walimpls/impls/kafka/builder.go +++ b/pkg/streaming/walimpls/impls/kafka/builder.go @@ -9,23 +9,19 @@ import ( "github.com/milvus-io/milvus/pkg/v2/util/paramtable" ) -const ( - walName = "kafka" -) - func init() { // register the builder to the wal registry. registry.RegisterBuilder(&builderImpl{}) // register the unmarshaler to the message registry. - message.RegisterMessageIDUnmsarshaler(walName, UnmarshalMessageID) + message.RegisterMessageIDUnmsarshaler(message.WALNameKafka, UnmarshalMessageID) } // builderImpl is the builder for pulsar wal. type builderImpl struct{} // Name returns the name of the wal. -func (b *builderImpl) Name() string { - return walName +func (b *builderImpl) Name() message.WALName { + return message.WALNameKafka } // Build build a wal instance. diff --git a/pkg/streaming/walimpls/impls/kafka/kafka_test.go b/pkg/streaming/walimpls/impls/kafka/kafka_test.go index 2c771fd1e0..44ee314279 100644 --- a/pkg/streaming/walimpls/impls/kafka/kafka_test.go +++ b/pkg/streaming/walimpls/impls/kafka/kafka_test.go @@ -5,6 +5,7 @@ import ( "github.com/stretchr/testify/assert" + "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" "github.com/milvus-io/milvus/pkg/v2/streaming/walimpls" "github.com/milvus-io/milvus/pkg/v2/streaming/walimpls/registry" @@ -17,12 +18,11 @@ func TestMain(m *testing.M) { } func TestRegistry(t *testing.T) { - registeredB := registry.MustGetBuilder(walName) + registeredB := registry.MustGetBuilder(message.WALNameKafka) assert.NotNil(t, registeredB) - assert.Equal(t, walName, registeredB.Name()) + assert.Equal(t, message.WALNameKafka, registeredB.Name()) - id, err := message.UnmarshalMessageID(walName, - kafkaID(123).Marshal()) + id, err := message.UnmarshalMessageID(&commonpb.MessageID{WALName: commonpb.WALName(message.WALNameKafka), Id: kafkaID(123).Marshal()}) assert.NoError(t, err) assert.True(t, id.EQ(kafkaID(123))) } diff --git a/pkg/streaming/walimpls/impls/kafka/message_id.go b/pkg/streaming/walimpls/impls/kafka/message_id.go index c565377d10..ab4da73fdc 100644 --- a/pkg/streaming/walimpls/impls/kafka/message_id.go +++ b/pkg/streaming/walimpls/impls/kafka/message_id.go @@ -6,6 +6,7 @@ import ( "github.com/cockroachdb/errors" "github.com/confluentinc/confluent-kafka-go/kafka" + "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" ) @@ -39,8 +40,8 @@ func (id kafkaID) KafkaID() kafka.Offset { } // WALName returns the name of message id related wal. -func (id kafkaID) WALName() string { - return walName +func (id kafkaID) WALName() message.WALName { + return message.WALNameKafka } // LT less than. @@ -63,6 +64,14 @@ func (id kafkaID) Marshal() string { return message.EncodeInt64(int64(id)) } +// IntoProto marshal the message id to proto. +func (id kafkaID) IntoProto() *commonpb.MessageID { + return &commonpb.MessageID{ + Id: id.Marshal(), + WALName: commonpb.WALName(id.WALName()), + } +} + func (id kafkaID) String() string { return strconv.FormatInt(int64(id), 10) } diff --git a/pkg/streaming/walimpls/impls/kafka/message_id_test.go b/pkg/streaming/walimpls/impls/kafka/message_id_test.go index 803bd5695f..133f76529d 100644 --- a/pkg/streaming/walimpls/impls/kafka/message_id_test.go +++ b/pkg/streaming/walimpls/impls/kafka/message_id_test.go @@ -12,7 +12,7 @@ import ( func TestMessageID(t *testing.T) { assert.Equal(t, kafka.Offset(1), message.MessageID(kafkaID(1)).(interface{ KafkaID() kafka.Offset }).KafkaID()) - assert.Equal(t, walName, kafkaID(1).WALName()) + assert.Equal(t, message.WALNameKafka, kafkaID(1).WALName()) assert.True(t, kafkaID(1).LT(kafkaID(2))) assert.True(t, kafkaID(1).EQ(kafkaID(1))) diff --git a/pkg/streaming/walimpls/impls/kafka/wal.go b/pkg/streaming/walimpls/impls/kafka/wal.go index 66ceb361d1..0967570ba2 100644 --- a/pkg/streaming/walimpls/impls/kafka/wal.go +++ b/pkg/streaming/walimpls/impls/kafka/wal.go @@ -21,8 +21,8 @@ type walImpl struct { consumerConfig kafka.ConfigMap } -func (w *walImpl) WALName() string { - return walName +func (w *walImpl) WALName() message.WALName { + return message.WALNameKafka } func (w *walImpl) Append(ctx context.Context, msg message.MutableMessage) (message.MessageID, error) { diff --git a/pkg/streaming/walimpls/impls/pulsar/builder.go b/pkg/streaming/walimpls/impls/pulsar/builder.go index a50f4660cc..1b3d9e6646 100644 --- a/pkg/streaming/walimpls/impls/pulsar/builder.go +++ b/pkg/streaming/walimpls/impls/pulsar/builder.go @@ -14,23 +14,19 @@ import ( "github.com/milvus-io/milvus/pkg/v2/util/paramtable" ) -const ( - walName = "pulsar" -) - func init() { // register the builder to the wal registry. registry.RegisterBuilder(&builderImpl{}) // register the unmarshaler to the message registry. - message.RegisterMessageIDUnmsarshaler(walName, UnmarshalMessageID) + message.RegisterMessageIDUnmsarshaler(message.WALNamePulsar, UnmarshalMessageID) } // builderImpl is the builder for pulsar wal. type builderImpl struct{} // Name returns the name of the wal. -func (b *builderImpl) Name() string { - return walName +func (b *builderImpl) Name() message.WALName { + return message.WALNamePulsar } // Build build a wal instance. diff --git a/pkg/streaming/walimpls/impls/pulsar/message_id.go b/pkg/streaming/walimpls/impls/pulsar/message_id.go index 34cb985297..d830028197 100644 --- a/pkg/streaming/walimpls/impls/pulsar/message_id.go +++ b/pkg/streaming/walimpls/impls/pulsar/message_id.go @@ -7,6 +7,7 @@ import ( "github.com/apache/pulsar-client-go/pulsar" "github.com/cockroachdb/errors" + "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" ) @@ -49,8 +50,8 @@ func (id pulsarID) PulsarID() pulsar.MessageID { return id.MessageID } -func (id pulsarID) WALName() string { - return walName +func (id pulsarID) WALName() message.WALName { + return message.WALNamePulsar } func (id pulsarID) LT(other message.MessageID) bool { @@ -86,6 +87,13 @@ func (id pulsarID) Marshal() string { return base64.StdEncoding.EncodeToString(id.Serialize()) } +func (id pulsarID) IntoProto() *commonpb.MessageID { + return &commonpb.MessageID{ + Id: id.Marshal(), + WALName: commonpb.WALName(id.WALName()), + } +} + func (id pulsarID) String() string { return fmt.Sprintf("%d/%d/%d", id.LedgerID(), id.EntryID(), id.BatchIdx()) } diff --git a/pkg/streaming/walimpls/impls/pulsar/message_id_test.go b/pkg/streaming/walimpls/impls/pulsar/message_id_test.go index 32f60af8d0..8eb9dbdd01 100644 --- a/pkg/streaming/walimpls/impls/pulsar/message_id_test.go +++ b/pkg/streaming/walimpls/impls/pulsar/message_id_test.go @@ -12,7 +12,7 @@ import ( func TestMessageID(t *testing.T) { pid := message.MessageID(newMessageIDOfPulsar(1, 2, 3)).(interface{ PulsarID() pulsar.MessageID }).PulsarID() - assert.Equal(t, walName, newMessageIDOfPulsar(1, 2, 3).WALName()) + assert.Equal(t, message.WALNamePulsar, newMessageIDOfPulsar(1, 2, 3).WALName()) assert.Equal(t, int64(1), pid.LedgerID()) assert.Equal(t, int64(2), pid.EntryID()) diff --git a/pkg/streaming/walimpls/impls/pulsar/pulsar_test.go b/pkg/streaming/walimpls/impls/pulsar/pulsar_test.go index e565d7341c..f06d30d37e 100644 --- a/pkg/streaming/walimpls/impls/pulsar/pulsar_test.go +++ b/pkg/streaming/walimpls/impls/pulsar/pulsar_test.go @@ -5,6 +5,7 @@ import ( "github.com/stretchr/testify/assert" + "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" "github.com/milvus-io/milvus/pkg/v2/streaming/walimpls" "github.com/milvus-io/milvus/pkg/v2/streaming/walimpls/registry" @@ -17,12 +18,14 @@ func TestMain(m *testing.M) { } func TestRegistry(t *testing.T) { - registeredB := registry.MustGetBuilder(walName) + registeredB := registry.MustGetBuilder(message.WALNamePulsar) assert.NotNil(t, registeredB) - assert.Equal(t, walName, registeredB.Name()) + assert.Equal(t, message.WALNamePulsar, registeredB.Name()) - id, err := message.UnmarshalMessageID(walName, - newMessageIDOfPulsar(1, 2, 3).Marshal()) + id, err := message.UnmarshalMessageID(&commonpb.MessageID{ + WALName: commonpb.WALName(message.WALNamePulsar), + Id: newMessageIDOfPulsar(1, 2, 3).Marshal(), + }) assert.NoError(t, err) assert.True(t, id.EQ(newMessageIDOfPulsar(1, 2, 3))) } diff --git a/pkg/streaming/walimpls/impls/pulsar/wal.go b/pkg/streaming/walimpls/impls/pulsar/wal.go index e7ac49c568..a5129d7de0 100644 --- a/pkg/streaming/walimpls/impls/pulsar/wal.go +++ b/pkg/streaming/walimpls/impls/pulsar/wal.go @@ -70,8 +70,8 @@ func (w *walImpl) initProducer() error { return nil } -func (w *walImpl) WALName() string { - return walName +func (w *walImpl) WALName() message.WALName { + return message.WALNamePulsar } func (w *walImpl) Append(ctx context.Context, msg message.MutableMessage) (message.MessageID, error) { diff --git a/pkg/streaming/walimpls/impls/rmq/builder.go b/pkg/streaming/walimpls/impls/rmq/builder.go index aa62ef80d0..636da25354 100644 --- a/pkg/streaming/walimpls/impls/rmq/builder.go +++ b/pkg/streaming/walimpls/impls/rmq/builder.go @@ -8,23 +8,19 @@ import ( "github.com/milvus-io/milvus/pkg/v2/streaming/walimpls/registry" ) -const ( - WALName = "rocksmq" -) - func init() { // register the builder to the registry. registry.RegisterBuilder(&builderImpl{}) // register the unmarshaler to the message registry. - message.RegisterMessageIDUnmsarshaler(WALName, UnmarshalMessageID) + message.RegisterMessageIDUnmsarshaler(message.WALNameRocksmq, UnmarshalMessageID) } // builderImpl is the builder for rmq opener. type builderImpl struct{} // Name of the wal builder, should be a lowercase string. -func (b *builderImpl) Name() string { - return WALName +func (b *builderImpl) Name() message.WALName { + return message.WALNameRocksmq } // Build build a wal instance. diff --git a/pkg/streaming/walimpls/impls/rmq/message_id.go b/pkg/streaming/walimpls/impls/rmq/message_id.go index f1ea5c574c..cc1a47cea9 100644 --- a/pkg/streaming/walimpls/impls/rmq/message_id.go +++ b/pkg/streaming/walimpls/impls/rmq/message_id.go @@ -5,6 +5,7 @@ import ( "github.com/cockroachdb/errors" + "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" ) @@ -45,8 +46,8 @@ func (id rmqID) RmqID() int64 { } // WALName returns the name of message id related wal. -func (id rmqID) WALName() string { - return WALName +func (id rmqID) WALName() message.WALName { + return message.WALNameRocksmq } // LT less than. @@ -69,6 +70,14 @@ func (id rmqID) Marshal() string { return message.EncodeInt64(int64(id)) } +// IntoProto marshal the message id to proto. +func (id rmqID) IntoProto() *commonpb.MessageID { + return &commonpb.MessageID{ + Id: message.EncodeInt64(int64(id)), + WALName: commonpb.WALName(id.WALName()), + } +} + func (id rmqID) String() string { return strconv.FormatInt(int64(id), 10) } diff --git a/pkg/streaming/walimpls/impls/rmq/message_id_test.go b/pkg/streaming/walimpls/impls/rmq/message_id_test.go index c03e139362..693f16b8ca 100644 --- a/pkg/streaming/walimpls/impls/rmq/message_id_test.go +++ b/pkg/streaming/walimpls/impls/rmq/message_id_test.go @@ -10,7 +10,7 @@ import ( func TestMessageID(t *testing.T) { assert.Equal(t, int64(1), message.MessageID(rmqID(1)).(interface{ RmqID() int64 }).RmqID()) - assert.Equal(t, WALName, rmqID(1).WALName()) + assert.Equal(t, message.WALNameRocksmq, rmqID(1).WALName()) assert.True(t, rmqID(1).LT(rmqID(2))) assert.True(t, rmqID(1).EQ(rmqID(1))) diff --git a/pkg/streaming/walimpls/impls/rmq/rmq_test.go b/pkg/streaming/walimpls/impls/rmq/rmq_test.go index 81943a5e87..f0037abb7b 100644 --- a/pkg/streaming/walimpls/impls/rmq/rmq_test.go +++ b/pkg/streaming/walimpls/impls/rmq/rmq_test.go @@ -6,6 +6,7 @@ import ( "github.com/stretchr/testify/assert" + "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" "github.com/milvus-io/milvus/pkg/v2/mq/mqimpl/rocksmq/server" "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" "github.com/milvus-io/milvus/pkg/v2/streaming/walimpls" @@ -26,11 +27,14 @@ func TestMain(m *testing.M) { } func TestRegistry(t *testing.T) { - registeredB := registry.MustGetBuilder(WALName) + registeredB := registry.MustGetBuilder(message.WALNameRocksmq) assert.NotNil(t, registeredB) - assert.Equal(t, WALName, registeredB.Name()) + assert.Equal(t, message.WALNameRocksmq, registeredB.Name()) - id, err := message.UnmarshalMessageID(WALName, rmqID(1).Marshal()) + id, err := message.UnmarshalMessageID(&commonpb.MessageID{ + WALName: commonpb.WALName(message.WALNameRocksmq), + Id: rmqID(1).Marshal(), + }) assert.NoError(t, err) assert.True(t, id.EQ(rmqID(1))) } diff --git a/pkg/streaming/walimpls/impls/rmq/wal.go b/pkg/streaming/walimpls/impls/rmq/wal.go index 408cb34c27..02281d5739 100644 --- a/pkg/streaming/walimpls/impls/rmq/wal.go +++ b/pkg/streaming/walimpls/impls/rmq/wal.go @@ -25,8 +25,8 @@ type walImpl struct { c client.Client } -func (w *walImpl) WALName() string { - return WALName +func (w *walImpl) WALName() message.WALName { + return message.WALNameRocksmq } // Append appends a message to the wal. diff --git a/pkg/streaming/walimpls/impls/walimplstest/builder.go b/pkg/streaming/walimpls/impls/walimplstest/builder.go index a7191ebfa4..258e3b8b23 100644 --- a/pkg/streaming/walimpls/impls/walimplstest/builder.go +++ b/pkg/streaming/walimpls/impls/walimplstest/builder.go @@ -9,22 +9,18 @@ import ( "github.com/milvus-io/milvus/pkg/v2/streaming/walimpls/registry" ) -const ( - WALName = "walimplstest" -) - func init() { // register the builder to the registry. registry.RegisterBuilder(&openerBuilder{}) - message.RegisterMessageIDUnmsarshaler(WALName, UnmarshalTestMessageID) + message.RegisterMessageIDUnmsarshaler(message.WALNameTest, UnmarshalTestMessageID) } var _ walimpls.OpenerBuilderImpls = &openerBuilder{} type openerBuilder struct{} -func (o *openerBuilder) Name() string { - return WALName +func (o *openerBuilder) Name() message.WALName { + return message.WALNameTest } func (o *openerBuilder) Build() (walimpls.OpenerImpls, error) { diff --git a/pkg/streaming/walimpls/impls/walimplstest/message_id.go b/pkg/streaming/walimpls/impls/walimplstest/message_id.go index 8d8a58b8f4..2f8db487d0 100644 --- a/pkg/streaming/walimpls/impls/walimplstest/message_id.go +++ b/pkg/streaming/walimpls/impls/walimplstest/message_id.go @@ -6,6 +6,7 @@ package walimplstest import ( "strconv" + "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" ) @@ -38,8 +39,8 @@ func unmarshalTestMessageID(data string) (testMessageID, error) { type testMessageID int64 // WALName returns the name of message id related wal. -func (id testMessageID) WALName() string { - return WALName +func (id testMessageID) WALName() message.WALName { + return message.WALNameTest } // LT less than. @@ -62,6 +63,14 @@ func (id testMessageID) Marshal() string { return strconv.FormatInt(int64(id), 10) } +// IntoProto marshal the message id to proto. +func (id testMessageID) IntoProto() *commonpb.MessageID { + return &commonpb.MessageID{ + Id: id.Marshal(), + WALName: commonpb.WALName(id.WALName()), + } +} + func (id testMessageID) String() string { return strconv.FormatInt(int64(id), 10) } diff --git a/pkg/streaming/walimpls/impls/walimplstest/wal.go b/pkg/streaming/walimpls/impls/walimplstest/wal.go index 14f0f13f79..26a650f1ec 100644 --- a/pkg/streaming/walimpls/impls/walimplstest/wal.go +++ b/pkg/streaming/walimpls/impls/walimplstest/wal.go @@ -39,8 +39,8 @@ type walImpls struct { datas *messageLog } -func (w *walImpls) WALName() string { - return WALName +func (w *walImpls) WALName() message.WALName { + return message.WALNameTest } func (w *walImpls) Append(ctx context.Context, msg message.MutableMessage) (message.MessageID, error) { diff --git a/pkg/streaming/walimpls/impls/wp/builder.go b/pkg/streaming/walimpls/impls/wp/builder.go index 269b6945e7..f9d5209542 100644 --- a/pkg/streaming/walimpls/impls/wp/builder.go +++ b/pkg/streaming/walimpls/impls/wp/builder.go @@ -22,23 +22,19 @@ import ( "github.com/milvus-io/milvus/pkg/v2/util/paramtable" ) -const ( - WALName = "woodpecker" -) - func init() { // register the builder to the wal registry. registry.RegisterBuilder(&builderImpl{}) // register the unmarshaler to the message registry. - message.RegisterMessageIDUnmsarshaler(WALName, UnmarshalMessageID) + message.RegisterMessageIDUnmsarshaler(message.WALNameWoodpecker, UnmarshalMessageID) } // builderImpl is the builder for woodpecker opener. type builderImpl struct{} // Name of the wal builder, should be a lowercase string. -func (b *builderImpl) Name() string { - return WALName +func (b *builderImpl) Name() message.WALName { + return message.WALNameWoodpecker } // Build build a wal instance. diff --git a/pkg/streaming/walimpls/impls/wp/message_id.go b/pkg/streaming/walimpls/impls/wp/message_id.go index 95c184a0ea..149f0e79a9 100644 --- a/pkg/streaming/walimpls/impls/wp/message_id.go +++ b/pkg/streaming/walimpls/impls/wp/message_id.go @@ -7,6 +7,7 @@ import ( "github.com/cockroachdb/errors" wp "github.com/zilliztech/woodpecker/woodpecker/log" + "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" ) @@ -50,8 +51,8 @@ func (id wpID) WoodpeckerMsgId() *wp.LogMessageId { return id.logMsgId } -func (id wpID) WALName() string { - return WALName +func (id wpID) WALName() message.WALName { + return message.WALNameWoodpecker } func (id wpID) LT(other message.MessageID) bool { @@ -81,6 +82,13 @@ func (id wpID) Marshal() string { return base64.StdEncoding.EncodeToString(id.logMsgId.Serialize()) } +func (id wpID) IntoProto() *commonpb.MessageID { + return &commonpb.MessageID{ + Id: id.Marshal(), + WALName: commonpb.WALName(id.WALName()), + } +} + func (id wpID) String() string { return fmt.Sprintf("%d/%d", id.logMsgId.SegmentId, id.logMsgId.EntryId) } diff --git a/pkg/streaming/walimpls/impls/wp/message_id_test.go b/pkg/streaming/walimpls/impls/wp/message_id_test.go index 50310d0247..b8e0d61afc 100644 --- a/pkg/streaming/walimpls/impls/wp/message_id_test.go +++ b/pkg/streaming/walimpls/impls/wp/message_id_test.go @@ -14,7 +14,7 @@ func TestMessageID(t *testing.T) { wpId := message.MessageID(newMessageIDOfWoodpecker(1, 2)).(interface { WoodpeckerID() *woodpecker.LogMessageId }).WoodpeckerID() - assert.Equal(t, WALName, newMessageIDOfWoodpecker(1, 2).WALName()) + assert.Equal(t, message.WALNameWoodpecker, newMessageIDOfWoodpecker(1, 2).WALName()) assert.Equal(t, int64(1), wpId.SegmentId) assert.Equal(t, int64(2), wpId.EntryId) diff --git a/pkg/streaming/walimpls/impls/wp/wal.go b/pkg/streaming/walimpls/impls/wp/wal.go index 6871d3ddc8..3ace181dc9 100644 --- a/pkg/streaming/walimpls/impls/wp/wal.go +++ b/pkg/streaming/walimpls/impls/wp/wal.go @@ -23,8 +23,8 @@ type walImpl struct { l wp.LogHandle } -func (w *walImpl) WALName() string { - return WALName +func (w *walImpl) WALName() message.WALName { + return message.WALNameWoodpecker } func (w *walImpl) Append(ctx context.Context, msg message.MutableMessage) (message.MessageID, error) { diff --git a/pkg/streaming/walimpls/impls/wp/wp_test.go b/pkg/streaming/walimpls/impls/wp/wp_test.go index a90fcf48c8..4e9c5fdb25 100644 --- a/pkg/streaming/walimpls/impls/wp/wp_test.go +++ b/pkg/streaming/walimpls/impls/wp/wp_test.go @@ -7,6 +7,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/zilliztech/woodpecker/woodpecker" + "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" "github.com/milvus-io/milvus/pkg/v2/streaming/walimpls" "github.com/milvus-io/milvus/pkg/v2/streaming/walimpls/registry" @@ -19,11 +20,14 @@ func TestMain(m *testing.M) { } func TestRegistry(t *testing.T) { - registeredB := registry.MustGetBuilder(WALName) + registeredB := registry.MustGetBuilder(message.WALNameWoodpecker) assert.NotNil(t, registeredB) - assert.Equal(t, WALName, registeredB.Name()) + assert.Equal(t, message.WALNameWoodpecker, registeredB.Name()) - id, err := message.UnmarshalMessageID(WALName, newMessageIDOfWoodpecker(1, 2).Marshal()) + id, err := message.UnmarshalMessageID(&commonpb.MessageID{ + WALName: commonpb.WALName(message.WALNameWoodpecker), + Id: newMessageIDOfWoodpecker(1, 2).Marshal(), + }) assert.NoError(t, err) assert.True(t, id.EQ(newMessageIDOfWoodpecker(1, 2))) } diff --git a/pkg/streaming/walimpls/registry/registry.go b/pkg/streaming/walimpls/registry/registry.go index 4f20563aa5..36509ecbe0 100644 --- a/pkg/streaming/walimpls/registry/registry.go +++ b/pkg/streaming/walimpls/registry/registry.go @@ -1,12 +1,13 @@ package registry import ( + "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" "github.com/milvus-io/milvus/pkg/v2/streaming/walimpls" "github.com/milvus-io/milvus/pkg/v2/util/typeutil" ) // builders is a map of registered wal builders. -var builders typeutil.ConcurrentMap[string, walimpls.OpenerBuilderImpls] +var builders typeutil.ConcurrentMap[message.WALName, walimpls.OpenerBuilderImpls] // Register registers the wal builder. // @@ -16,15 +17,15 @@ var builders typeutil.ConcurrentMap[string, walimpls.OpenerBuilderImpls] func RegisterBuilder(b walimpls.OpenerBuilderImpls) { _, loaded := builders.GetOrInsert(b.Name(), b) if loaded { - panic("walimpls builder already registered: " + b.Name()) + panic("walimpls builder already registered: " + b.Name().String()) } } // MustGetBuilder returns the walimpls builder by name. -func MustGetBuilder(name string) walimpls.OpenerBuilderImpls { +func MustGetBuilder(name message.WALName) walimpls.OpenerBuilderImpls { b, ok := builders.Get(name) if !ok { - panic("walimpls builder not found: " + name) + panic("walimpls builder not found: " + name.String()) } return b } diff --git a/pkg/streaming/walimpls/registry/wal_test.go b/pkg/streaming/walimpls/registry/wal_test.go index 6c330d483d..9c1607d34c 100644 --- a/pkg/streaming/walimpls/registry/wal_test.go +++ b/pkg/streaming/walimpls/registry/wal_test.go @@ -1,17 +1,17 @@ package registry import ( - "fmt" "sync" "testing" "github.com/stretchr/testify/assert" "github.com/milvus-io/milvus/pkg/v2/mocks/streaming/mock_walimpls" + "github.com/milvus-io/milvus/pkg/v2/streaming/util/message" ) func TestRegister(t *testing.T) { - name := "mock" + name := message.WALNameUnknown b := mock_walimpls.NewMockOpenerBuilderImpls(t) b.EXPECT().Name().Return(name) @@ -26,17 +26,17 @@ func TestRegister(t *testing.T) { // Panic if get not exist builder. assert.Panics(t, func() { - MustGetBuilder("not exist") + MustGetBuilder(message.WALName(100)) }) // Test concurrent. wg := sync.WaitGroup{} count := 10 wg.Add(count) - for i := 0; i < count; i++ { + for i := 1; i <= count; i++ { go func(i int) { defer wg.Done() - name := fmt.Sprintf("mock_%d", i) + name := message.WALName(i) b := mock_walimpls.NewMockOpenerBuilderImpls(t) b.EXPECT().Name().Return(name) RegisterBuilder(b) diff --git a/pkg/streaming/walimpls/wal.go b/pkg/streaming/walimpls/wal.go index a008069216..872216945b 100644 --- a/pkg/streaming/walimpls/wal.go +++ b/pkg/streaming/walimpls/wal.go @@ -14,7 +14,7 @@ var ErrFenced = errors.New("fenced") // ROWALImpls is the underlying implementation for a read-only wal. type ROWALImpls interface { // WALName returns the name of the wal. - WALName() string + WALName() message.WALName // Channel returns the channel assignment info of the wal. // Should be read-only. diff --git a/pkg/util/replicateutil/config_helper.go b/pkg/util/replicateutil/config_helper.go new file mode 100644 index 0000000000..56623b0f3a --- /dev/null +++ b/pkg/util/replicateutil/config_helper.go @@ -0,0 +1,214 @@ +// Licensed to the LF AI & Data foundation under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The 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 replicateutil + +import ( + "fmt" + + "github.com/cockroachdb/errors" + + "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" + "github.com/milvus-io/milvus/pkg/v2/util/typeutil" +) + +type Role int + +const ( + RolePrimary Role = iota + RoleSecondary +) + +var ErrWrongConfiguration = errors.New("wrong replicate configuration") + +func (r Role) String() string { + switch r { + case RolePrimary: + return "primary" + case RoleSecondary: + return "secondary" + default: + panic(r) + } +} + +// MustNewConfigHelper creates a new graph from the replicate configuration. +func MustNewConfigHelper(currentClusterID string, cfg *commonpb.ReplicateConfiguration) *ConfigHelper { + g, err := NewConfigHelper(currentClusterID, cfg) + if err != nil { + panic(err) + } + return g +} + +// NewConfigHelper creates a new graph from the replicate configuration. +func NewConfigHelper(currentClusterID string, cfg *commonpb.ReplicateConfiguration) (*ConfigHelper, error) { + if cfg == nil { + return nil, nil + } + h := &ConfigHelper{} + vs := make(map[string]*MilvusCluster) + for _, cluster := range cfg.GetClusters() { + vs[cluster.GetClusterId()] = &MilvusCluster{ + h: h, + MilvusCluster: cluster, + idxMap: make(map[string]int), + role: RolePrimary, + source: "", + targets: typeutil.NewSet[string](), + } + for i, pchannel := range cluster.Pchannels { + vs[cluster.GetClusterId()].idxMap[pchannel] = i + } + } + for _, topology := range cfg.GetCrossClusterTopology() { + if _, ok := vs[topology.SourceClusterId]; !ok { + return nil, ErrWrongConfiguration + } + if _, ok := vs[topology.TargetClusterId]; !ok { + return nil, ErrWrongConfiguration + } + if vs[topology.SourceClusterId].targets.Contain(topology.TargetClusterId) { + return nil, ErrWrongConfiguration + } + if vs[topology.TargetClusterId].source != "" { + return nil, ErrWrongConfiguration + } + vs[topology.TargetClusterId].source = topology.SourceClusterId + vs[topology.TargetClusterId].role = RoleSecondary + vs[topology.SourceClusterId].targets.Insert(topology.TargetClusterId) + } + primaryCount := 0 + for _, vertice := range vs { + if vertice.role == RolePrimary { + primaryCount++ + } + } + if primaryCount != 1 { + return nil, errors.Wrap(ErrWrongConfiguration, "primary count is not 1") + } + if _, ok := vs[currentClusterID]; !ok { + return nil, errors.Wrap(ErrWrongConfiguration, fmt.Sprintf("current cluster %s not found", currentClusterID)) + } + pchannels := len(vs[currentClusterID].Pchannels) + for _, vertice := range vs { + if len(vertice.Pchannels) != pchannels { + return nil, errors.Wrap(ErrWrongConfiguration, fmt.Sprintf("pchannel count is not equal for cluster %s", vertice.GetClusterId())) + } + } + h.currentClusterID = currentClusterID + h.cfg = cfg + h.vs = vs + return h, nil +} + +// ConfigHelper describes the replicate topology. +type ConfigHelper struct { + currentClusterID string + cfg *commonpb.ReplicateConfiguration + vs map[string]*MilvusCluster +} + +// GetReplicateConfiguration returns the replicate configuration of the graph. +func (g *ConfigHelper) GetReplicateConfiguration() *commonpb.ReplicateConfiguration { + return g.cfg +} + +// GetCurrentCluster returns the current cluster id. +func (g *ConfigHelper) GetCurrentCluster() *MilvusCluster { + return g.vs[g.currentClusterID] +} + +// GetCluster returns the cluster from the graph. +func (g *ConfigHelper) GetCluster(clusterID string) *MilvusCluster { + return g.vs[clusterID] +} + +// MustGetCluster returns the cluster from the graph. +func (g *ConfigHelper) MustGetCluster(clusterID string) *MilvusCluster { + vertice, ok := g.vs[clusterID] + if !ok { + panic(fmt.Sprintf("cluster %s not found", clusterID)) + } + return vertice +} + +// MilvusCluster describes the replicate topology. +type MilvusCluster struct { + *commonpb.MilvusCluster + h *ConfigHelper + role Role + idxMap map[string]int + source string + targets typeutil.Set[string] +} + +// Role returns the role of the milvus cluster. +func (v *MilvusCluster) Role() Role { + return v.role +} + +// SourceCluster returns the source cluster of the milvus. +// return nil if the milvus cluster is a primary node. +func (v *MilvusCluster) SourceCluster() *MilvusCluster { + if v.role == RolePrimary { + return nil + } + return v.h.vs[v.source] +} + +// TargetClusters returns the target clusters of the milvus. +func (v *MilvusCluster) TargetClusters() []*MilvusCluster { + targets := make([]*MilvusCluster, 0, len(v.targets)) + for target := range v.targets { + targets = append(targets, v.h.vs[target]) + } + return targets +} + +// TargetCluster returns the target cluster of the milvus. +func (v *MilvusCluster) TargetCluster(targetClusterID string) *MilvusCluster { + if !v.targets.Contain(targetClusterID) { + return nil + } + return v.h.vs[targetClusterID] +} + +// MustGetSourceChannel returns the source channel by the current cluster channel. +func (v *MilvusCluster) MustGetSourceChannel(pchannel string) string { + source := v.SourceCluster() + if source == nil { + panic(fmt.Sprintf("source cluster not found for milvus cluster %s", v.GetClusterId())) + } + idx, ok := v.idxMap[pchannel] + if !ok { + panic(fmt.Sprintf("channel of current cluster not found for pchannel: %s", pchannel)) + } + return source.Pchannels[idx] +} + +// GetTargetChannel returns the target channel of the current cluster. +func (v *MilvusCluster) GetTargetChannel(currentClusterPChannel string, targetClusterID string) (string, error) { + if !v.targets.Contain(targetClusterID) { + return "", errors.Errorf("target cluster %s not found, current cluster is %s", targetClusterID, v.GetClusterId()) + } + idx, ok := v.idxMap[currentClusterPChannel] + if !ok { + return "", errors.Errorf("current cluster pchannel %s not found in the graph", currentClusterPChannel) + } + target := v.h.vs[targetClusterID] + return target.Pchannels[idx], nil +} diff --git a/pkg/util/replicateutil/config_helper_test.go b/pkg/util/replicateutil/config_helper_test.go new file mode 100644 index 0000000000..3adbd3676b --- /dev/null +++ b/pkg/util/replicateutil/config_helper_test.go @@ -0,0 +1,436 @@ +// Licensed to the LF AI & Data foundation under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The 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 replicateutil + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" +) + +// createValidConfig creates a valid ReplicateConfiguration for testing +func createValidConfig() *commonpb.ReplicateConfiguration { + return &commonpb.ReplicateConfiguration{ + Clusters: []*commonpb.MilvusCluster{ + { + ClusterId: "source-cluster", + ConnectionParam: &commonpb.ConnectionParam{ + Uri: "localhost:19530", + Token: "test-token", + }, + Pchannels: []string{"source-cluster-channel-1", "source-cluster-channel-2"}, + }, + { + ClusterId: "target-cluster-a", + ConnectionParam: &commonpb.ConnectionParam{ + Uri: "localhost:19531", + Token: "test-token", + }, + Pchannels: []string{"target-cluster-a-channel-1", "target-cluster-a-channel-2"}, + }, + { + ClusterId: "target-cluster-b", + ConnectionParam: &commonpb.ConnectionParam{ + Uri: "localhost:19532", + Token: "test-token", + }, + Pchannels: []string{"target-cluster-b-channel-1", "target-cluster-b-channel-2"}, + }, + }, + CrossClusterTopology: []*commonpb.CrossClusterTopology{ + { + SourceClusterId: "source-cluster", + TargetClusterId: "target-cluster-a", + }, + { + SourceClusterId: "source-cluster", + TargetClusterId: "target-cluster-b", + }, + }, + } +} + +// createConfigWithDifferentChannelCounts creates a config with different channel counts for edge case testing +func createConfigWithDifferentChannelCounts() *commonpb.ReplicateConfiguration { + return &commonpb.ReplicateConfiguration{ + Clusters: []*commonpb.MilvusCluster{ + { + ClusterId: "source-cluster", + ConnectionParam: &commonpb.ConnectionParam{ + Uri: "localhost:19530", + Token: "test-token", + }, + Pchannels: []string{"source-channel-1", "source-channel-2", "source-channel-3"}, + }, + { + ClusterId: "target-cluster-a", + ConnectionParam: &commonpb.ConnectionParam{ + Uri: "localhost:19531", + Token: "test-token", + }, + Pchannels: []string{"target-channel-1", "target-channel-2"}, + }, + }, + CrossClusterTopology: []*commonpb.CrossClusterTopology{ + { + SourceClusterId: "source-cluster", + TargetClusterId: "target-cluster-a", + }, + }, + } +} + +func TestNewConfigHelper(t *testing.T) { + tests := []struct { + name string + config *commonpb.ReplicateConfiguration + }{ + { + name: "success - valid config", + config: createValidConfig(), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + helper := MustNewConfigHelper("source-cluster", tt.config) + assert.NotNil(t, helper) + }) + } +} + +func TestConfigHelper_GetCluster(t *testing.T) { + config := createValidConfig() + helper := MustNewConfigHelper("source-cluster", config) + + tests := []struct { + name string + clusterID string + wantErr bool + expected *commonpb.MilvusCluster + }{ + { + name: "success - find source cluster", + clusterID: "source-cluster", + wantErr: false, + expected: config.GetClusters()[0], + }, + { + name: "success - find target cluster a", + clusterID: "target-cluster-a", + wantErr: false, + expected: config.GetClusters()[1], + }, + { + name: "success - find target cluster b", + clusterID: "target-cluster-b", + wantErr: false, + expected: config.GetClusters()[2], + }, + { + name: "panic - cluster not found", + clusterID: "non-existent-cluster", + wantErr: true, + expected: nil, + }, + { + name: "panic - empty cluster ID", + clusterID: "", + wantErr: true, + expected: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if tt.wantErr { + result := helper.GetCluster(tt.clusterID) + assert.Nil(t, result) + } else { + result := helper.GetCluster(tt.clusterID) + assert.Equal(t, tt.expected, result.MilvusCluster) + } + }) + } +} + +func TestConfigHelper_GetSourceCluster(t *testing.T) { + config := createValidConfig() + helper := MustNewConfigHelper("target-cluster-a", config) + + t.Run("success - get source cluster", func(t *testing.T) { + result := helper.GetCurrentCluster().SourceCluster() + assert.NotNil(t, result) + assert.Equal(t, "source-cluster", result.GetClusterId()) + assert.Equal(t, config.GetClusters()[0], result.MilvusCluster) + }) +} + +func TestConfigHelper_GetTargetClusters(t *testing.T) { + config := createValidConfig() + helper := MustNewConfigHelper("source-cluster", config) + + t.Run("success - get target clusters", func(t *testing.T) { + result := helper.GetCurrentCluster().TargetClusters() + assert.Len(t, result, 2) + + // Check that we have both target clusters + clusterIDs := make(map[string]bool) + for _, cluster := range result { + clusterIDs[cluster.GetClusterId()] = true + } + assert.True(t, clusterIDs["target-cluster-a"]) + assert.True(t, clusterIDs["target-cluster-b"]) + }) +} + +func TestConfigHelper_GetSourceChannel(t *testing.T) { + config := createValidConfig() + helper := MustNewConfigHelper("source-cluster", config) + + tests := []struct { + name string + clusterID string + targetChannelName string + wantErr bool + expected string + }{ + { + name: "success - get source channel for target cluster a channel 1", + clusterID: "target-cluster-a", + targetChannelName: "target-cluster-a-channel-1", + wantErr: false, + expected: "source-cluster-channel-1", + }, + { + name: "success - get source channel for target cluster a channel 2", + clusterID: "target-cluster-a", + targetChannelName: "target-cluster-a-channel-2", + wantErr: false, + expected: "source-cluster-channel-2", + }, + { + name: "success - get source channel for target cluster b channel 1", + clusterID: "target-cluster-b", + targetChannelName: "target-cluster-b-channel-1", + wantErr: false, + expected: "source-cluster-channel-1", + }, + { + name: "success - get source channel for target cluster b channel 2", + clusterID: "target-cluster-b", + targetChannelName: "target-cluster-b-channel-2", + wantErr: false, + expected: "source-cluster-channel-2", + }, + { + name: "panic - target channel not found", + clusterID: "target-cluster-a", + targetChannelName: "non-existent-channel", + wantErr: true, + expected: "", + }, + { + name: "panic - empty target channel name", + clusterID: "target-cluster-a", + targetChannelName: "", + wantErr: true, + expected: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if tt.wantErr { + assert.Panics(t, func() { + helper.GetCluster(tt.clusterID).MustGetSourceChannel(tt.targetChannelName) + }) + } else { + result := helper.GetCluster(tt.clusterID).MustGetSourceChannel(tt.targetChannelName) + assert.Equal(t, tt.expected, result) + } + }) + } +} + +func TestConfigHelper_GetTargetChannel(t *testing.T) { + config := createValidConfig() + helper := MustNewConfigHelper("source-cluster", config) + + tests := []struct { + name string + sourceChannelName string + targetClusterID string + wantErr bool + expected string + }{ + { + name: "success - get target channel for source channel 1 in cluster a", + sourceChannelName: "source-cluster-channel-1", + targetClusterID: "target-cluster-a", + wantErr: false, + expected: "target-cluster-a-channel-1", + }, + { + name: "success - get target channel for source channel 2 in cluster a", + sourceChannelName: "source-cluster-channel-2", + targetClusterID: "target-cluster-a", + wantErr: false, + expected: "target-cluster-a-channel-2", + }, + { + name: "success - get target channel for source channel 1 in cluster b", + sourceChannelName: "source-cluster-channel-1", + targetClusterID: "target-cluster-b", + wantErr: false, + expected: "target-cluster-b-channel-1", + }, + { + name: "success - get target channel for source channel 2 in cluster b", + sourceChannelName: "source-cluster-channel-2", + targetClusterID: "target-cluster-b", + wantErr: false, + expected: "target-cluster-b-channel-2", + }, + { + name: "panic - target cluster not found", + sourceChannelName: "source-cluster-channel-1", + targetClusterID: "non-existent-cluster", + wantErr: true, + expected: "", + }, + { + name: "panic - source channel not found in target cluster", + sourceChannelName: "non-existent-channel", + targetClusterID: "target-cluster-a", + wantErr: true, + expected: "", + }, + { + name: "panic - empty source channel name", + sourceChannelName: "", + targetClusterID: "target-cluster-a", + wantErr: true, + expected: "", + }, + { + name: "panic - empty target cluster ID", + sourceChannelName: "source-cluster-channel-1", + targetClusterID: "", + wantErr: true, + expected: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if tt.wantErr { + _, err := helper.GetCurrentCluster().GetTargetChannel(tt.sourceChannelName, tt.targetClusterID) + assert.Error(t, err) + } else { + result, err := helper.GetCurrentCluster().GetTargetChannel(tt.sourceChannelName, tt.targetClusterID) + assert.NoError(t, err) + assert.Equal(t, tt.expected, result) + } + }) + } +} + +func TestConfigHelper_EdgeCases(t *testing.T) { + t.Run("config with different channel counts", func(t *testing.T) { + config := createConfigWithDifferentChannelCounts() + // helper can not be created + assert.Panics(t, func() { + MustNewConfigHelper("source-cluster", config) + }) + }) + + t.Run("config with single cluster", func(t *testing.T) { + config := &commonpb.ReplicateConfiguration{ + Clusters: []*commonpb.MilvusCluster{ + { + ClusterId: "single-cluster", + ConnectionParam: &commonpb.ConnectionParam{ + Uri: "localhost:19530", + Token: "test-token", + }, + Pchannels: []string{"channel-1", "channel-2"}, + }, + }, + CrossClusterTopology: []*commonpb.CrossClusterTopology{}, + } + + helper := MustNewConfigHelper("single-cluster", config) + + // Source cluster should be nil when no topology is defined + assert.Nil(t, helper.GetCurrentCluster().SourceCluster()) + + // Target clusters should be empty + assert.Len(t, helper.GetCurrentCluster().TargetClusters(), 0) + }) + + t.Run("config with empty clusters", func(t *testing.T) { + config := &commonpb.ReplicateConfiguration{ + Clusters: []*commonpb.MilvusCluster{}, + CrossClusterTopology: []*commonpb.CrossClusterTopology{}, + } + + assert.Panics(t, func() { + MustNewConfigHelper("source-cluster", config) + }) + }) +} + +func TestConfigHelper_ChannelMappingConsistency(t *testing.T) { + config := createValidConfig() + helper := MustNewConfigHelper("source-cluster", config) + + t.Run("bidirectional channel mapping consistency", func(t *testing.T) { + // Test that source -> target -> source mapping is consistent + sourceChannel := "source-cluster-channel-1" + targetClusterID := "target-cluster-a" + + targetChannel, err := helper.GetCurrentCluster().GetTargetChannel(sourceChannel, targetClusterID) + assert.Equal(t, "target-cluster-a-channel-1", targetChannel) + assert.NoError(t, err) + + // Reverse mapping should give us back the original source channel + reverseSourceChannel := helper.GetCluster(targetClusterID).MustGetSourceChannel(targetChannel) + assert.Equal(t, sourceChannel, reverseSourceChannel) + }) + + t.Run("all channel mappings are consistent", func(t *testing.T) { + sourceCluster := helper.GetCurrentCluster() + targetClusters := helper.GetCurrentCluster().TargetClusters() + + for _, targetCluster := range targetClusters { + targetClusterID := targetCluster.GetClusterId() + + for i, sourceChannel := range sourceCluster.GetPchannels() { + targetChannel, err := helper.GetCurrentCluster().GetTargetChannel(sourceChannel, targetClusterID) + assert.NoError(t, err) + + // Verify the reverse mapping + reverseSourceChannel := helper.GetCluster(targetClusterID).MustGetSourceChannel(targetChannel) + assert.Equal(t, sourceChannel, reverseSourceChannel, + "Channel mapping inconsistency for cluster %s, channel index %d", targetClusterID, i) + } + } + }) +} diff --git a/pkg/util/replicateutil/config_validator.go b/pkg/util/replicateutil/config_validator.go new file mode 100644 index 0000000000..64786b9d77 --- /dev/null +++ b/pkg/util/replicateutil/config_validator.go @@ -0,0 +1,243 @@ +// Licensed to the LF AI & Data foundation under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The 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 replicateutil + +import ( + "fmt" + "net/url" + "strings" + + "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" +) + +// ReplicateConfigValidator validates ReplicateConfiguration according to business rules +type ReplicateConfigValidator struct { + currentClusterID string + currentPChannels []string + clusterMap map[string]*commonpb.MilvusCluster + config *commonpb.ReplicateConfiguration +} + +// NewReplicateConfigValidator creates a new validator instance with the given configuration +func NewReplicateConfigValidator(config *commonpb.ReplicateConfiguration, currentClusterID string, currentPChannels []string) *ReplicateConfigValidator { + validator := &ReplicateConfigValidator{ + currentClusterID: currentClusterID, + currentPChannels: currentPChannels, + clusterMap: make(map[string]*commonpb.MilvusCluster), + config: config, + } + return validator +} + +// Validate performs all validation checks on the configuration +func (v *ReplicateConfigValidator) Validate() error { + if v.config == nil { + return fmt.Errorf("config cannot be nil") + } + clusters := v.config.GetClusters() + if len(clusters) == 0 { + return fmt.Errorf("clusters list cannot be empty") + } + // Perform all validation checks + if err := v.validateClusterBasic(clusters); err != nil { + return err + } + if err := v.validateRelevance(); err != nil { + return err + } + topologies := v.config.GetCrossClusterTopology() + if err := v.validateTopologyEdgeUniqueness(topologies); err != nil { + return err + } + if err := v.validateTopologyTypeConstraint(topologies); err != nil { + return err + } + return nil +} + +// validateClusterBasic validates basic format requirements for each MilvusCluster +func (v *ReplicateConfigValidator) validateClusterBasic(clusters []*commonpb.MilvusCluster) error { + var expectedPchannelCount int + var firstClusterID string + for i, cluster := range clusters { + if cluster == nil { + return fmt.Errorf("cluster at index %d is nil", i) + } + // clusterID validation: non-empty and no whitespace + clusterID := cluster.GetClusterId() + if clusterID == "" { + return fmt.Errorf("cluster at index %d has empty clusterID", i) + } + if strings.ContainsAny(clusterID, " \t\n\r") { + return fmt.Errorf("cluster at index %d has clusterID '%s' containing whitespace characters", i, clusterID) + } + // connection_param.uri validation: non-empty and basic URI format + connParam := cluster.GetConnectionParam() + if connParam == nil { + return fmt.Errorf("cluster '%s' has nil connection_param", clusterID) + } + uri := connParam.GetUri() + if uri == "" { + return fmt.Errorf("cluster '%s' has empty URI", clusterID) + } + _, err := url.ParseRequestURI(uri) + if err != nil { + return fmt.Errorf("cluster '%s' has invalid URI format: '%s'", clusterID, uri) + } + // pchannels validation: non-empty + pchannels := cluster.GetPchannels() + if len(pchannels) == 0 { + return fmt.Errorf("cluster '%s' has empty pchannels", clusterID) + } + // pchannels uniqueness within cluster + pchannelSet := make(map[string]bool) + for j, pchannel := range pchannels { + if pchannel == "" { + return fmt.Errorf("cluster '%s' has empty pchannel at index %d", clusterID, j) + } + if pchannelSet[pchannel] { + return fmt.Errorf("cluster '%s' has duplicate pchannel: '%s'", clusterID, pchannel) + } + // Validate that pchannel starts with clusterID as prefix + if !strings.HasPrefix(pchannel, clusterID) { + return fmt.Errorf("cluster '%s' has pchannel '%s' that does not start with clusterID as prefix", clusterID, pchannel) + } + pchannelSet[pchannel] = true + } + // pchannels count consistency across all clusters + if i == 0 { + expectedPchannelCount = len(pchannels) + firstClusterID = clusterID + } else if len(pchannels) != expectedPchannelCount { + return fmt.Errorf("cluster '%s' has %d pchannels, but expected %d (same as cluster '%s')", + clusterID, len(pchannels), expectedPchannelCount, firstClusterID) + } + // Build cluster maps + if _, exists := v.clusterMap[clusterID]; exists { + return fmt.Errorf("duplicate clusterID found: '%s'", clusterID) + } + v.clusterMap[clusterID] = cluster + } + return nil +} + +// validateRelevance validates that clusters must contain current Milvus cluster +func (v *ReplicateConfigValidator) validateRelevance() error { + currentCluster, exists := v.clusterMap[v.currentClusterID] + if !exists { + return fmt.Errorf("current Milvus cluster '%s' must be included in the clusters list", v.currentClusterID) + } + if !equalIgnoreOrder(v.currentPChannels, currentCluster.GetPchannels()) { + return fmt.Errorf("current pchannels do not match the pchannels in the config, current pchannels: %v, config pchannels: %v", v.currentPChannels, currentCluster.GetPchannels()) + } + return nil +} + +// validateTopologyEdgeUniqueness validates that a given source_clusterID -> target_clusterID pair appears only once +func (v *ReplicateConfigValidator) validateTopologyEdgeUniqueness(topologies []*commonpb.CrossClusterTopology) error { + if len(topologies) == 0 { + return nil + } + edgeSet := make(map[string]struct{}) + for i, topology := range topologies { + if topology == nil { + return fmt.Errorf("topology at index %d is nil", i) + } + sourceClusterID := topology.GetSourceClusterId() + targetClusterID := topology.GetTargetClusterId() + // Validate edge endpoints exist + if _, exists := v.clusterMap[sourceClusterID]; !exists { + return fmt.Errorf("topology at index %d references non-existent source cluster: '%s'", i, sourceClusterID) + } + if _, exists := v.clusterMap[targetClusterID]; !exists { + return fmt.Errorf("topology at index %d references non-existent target cluster: '%s'", i, targetClusterID) + } + // Edge uniqueness + edgeKey := fmt.Sprintf("%s->%s", sourceClusterID, targetClusterID) + if _, exists := edgeSet[edgeKey]; exists { + return fmt.Errorf("duplicate topology relationship found: '%s'", edgeKey) + } + edgeSet[edgeKey] = struct{}{} + } + return nil +} + +// validateTopologyTypeConstraint validates that currently only STAR topology is supported +func (v *ReplicateConfigValidator) validateTopologyTypeConstraint(topologies []*commonpb.CrossClusterTopology) error { + if len(topologies) == 0 { + return nil + } + // Build in-degree and out-degree maps + inDegree := make(map[string]int) + outDegree := make(map[string]int) + // Initialize all clusters with 0 degrees + for clusterID := range v.clusterMap { + inDegree[clusterID] = 0 + outDegree[clusterID] = 0 + } + // Calculate degrees + for _, topology := range topologies { + source := topology.GetSourceClusterId() + target := topology.GetTargetClusterId() + outDegree[source]++ + inDegree[target]++ + } + // Find center node (out-degree = clusters-1, in-degree = 0) + var centerNode string + clusterCount := len(v.clusterMap) + for clusterID := range v.clusterMap { + if outDegree[clusterID] == clusterCount-1 && inDegree[clusterID] == 0 { + if centerNode != "" { + // Multiple center nodes found + return fmt.Errorf("multiple center nodes found, only one center node is allowed in star topology") + } + centerNode = clusterID + } + } + if centerNode == "" { + // No center node found + return fmt.Errorf("no center node found, star topology must have exactly one center node") + } + // Validate other nodes (in-degree = 1, out-degree = 0) + for clusterID := range v.clusterMap { + if clusterID == centerNode { + continue + } + if inDegree[clusterID] != 1 || outDegree[clusterID] != 0 { + return fmt.Errorf("cluster '%s' does not follow star topology pattern (in-degree=%d, out-degree=%d)", + clusterID, inDegree[clusterID], outDegree[clusterID]) + } + } + return nil +} + +func equalIgnoreOrder(a, b []string) bool { + if len(a) != len(b) { + return false + } + counts := make(map[string]int) + for _, v := range a { + counts[v]++ + } + for _, v := range b { + if counts[v] == 0 { + return false + } + counts[v]-- + } + return true +} diff --git a/pkg/util/replicateutil/config_validator_test.go b/pkg/util/replicateutil/config_validator_test.go new file mode 100644 index 0000000000..bec9afb396 --- /dev/null +++ b/pkg/util/replicateutil/config_validator_test.go @@ -0,0 +1,717 @@ +// Licensed to the LF AI & Data foundation under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The 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 replicateutil + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" +) + +// createValidValidatorConfig creates a valid ReplicateConfiguration for testing +func createValidValidatorConfig() *commonpb.ReplicateConfiguration { + return &commonpb.ReplicateConfiguration{ + Clusters: []*commonpb.MilvusCluster{ + { + ClusterId: "cluster-1", + ConnectionParam: &commonpb.ConnectionParam{ + Uri: "localhost:19530", + Token: "test-token", + }, + Pchannels: []string{"cluster-1-channel-1", "cluster-1-channel-2"}, + }, + { + ClusterId: "cluster-2", + ConnectionParam: &commonpb.ConnectionParam{ + Uri: "localhost:19531", + Token: "test-token", + }, + Pchannels: []string{"cluster-2-channel-1", "cluster-2-channel-2"}, + }, + }, + CrossClusterTopology: []*commonpb.CrossClusterTopology{ + { + SourceClusterId: "cluster-1", + TargetClusterId: "cluster-2", + }, + }, + } +} + +// createStarTopologyConfig creates a valid star topology configuration +func createStarTopologyConfig() *commonpb.ReplicateConfiguration { + return &commonpb.ReplicateConfiguration{ + Clusters: []*commonpb.MilvusCluster{ + { + ClusterId: "center-cluster", + ConnectionParam: &commonpb.ConnectionParam{ + Uri: "localhost:19530", + Token: "test-token", + }, + Pchannels: []string{"center-cluster-channel-1", "center-cluster-channel-2"}, + }, + { + ClusterId: "leaf-cluster-1", + ConnectionParam: &commonpb.ConnectionParam{ + Uri: "localhost:19531", + Token: "test-token", + }, + Pchannels: []string{"leaf-cluster-1-channel-1", "leaf-cluster-1-channel-2"}, + }, + { + ClusterId: "leaf-cluster-2", + ConnectionParam: &commonpb.ConnectionParam{ + Uri: "localhost:19532", + Token: "test-token", + }, + Pchannels: []string{"leaf-cluster-2-channel-1", "leaf-cluster-2-channel-2"}, + }, + }, + CrossClusterTopology: []*commonpb.CrossClusterTopology{ + { + SourceClusterId: "center-cluster", + TargetClusterId: "leaf-cluster-1", + }, + { + SourceClusterId: "center-cluster", + TargetClusterId: "leaf-cluster-2", + }, + }, + } +} + +func TestNewReplicateConfigValidator(t *testing.T) { + config := createValidValidatorConfig() + currentPChannels := []string{"cluster-1-channel-1", "cluster-1-channel-2"} + + t.Run("success - create validator", func(t *testing.T) { + validator := NewReplicateConfigValidator(config, "cluster-1", currentPChannels) + assert.NotNil(t, validator) + assert.Equal(t, config, validator.config) + assert.Equal(t, currentPChannels, validator.currentPChannels) + assert.NotNil(t, validator.clusterMap) + assert.Equal(t, 0, len(validator.clusterMap)) // clusterMap is built during validation + }) +} + +func TestReplicateConfigValidator_Validate(t *testing.T) { + t.Run("success - valid configuration", func(t *testing.T) { + config := createValidValidatorConfig() + currentPChannels := []string{"cluster-1-channel-1", "cluster-1-channel-2"} + validator := NewReplicateConfigValidator(config, "cluster-1", currentPChannels) + + err := validator.Validate() + assert.NoError(t, err) + }) + + t.Run("error - nil config", func(t *testing.T) { + validator := NewReplicateConfigValidator(nil, "cluster-1", []string{}) + err := validator.Validate() + assert.Error(t, err) + assert.Contains(t, err.Error(), "config cannot be nil") + }) + + t.Run("error - empty clusters", func(t *testing.T) { + config := &commonpb.ReplicateConfiguration{ + Clusters: []*commonpb.MilvusCluster{}, + CrossClusterTopology: []*commonpb.CrossClusterTopology{}, + } + validator := NewReplicateConfigValidator(config, "cluster-1", []string{}) + err := validator.Validate() + assert.Error(t, err) + assert.Contains(t, err.Error(), "clusters list cannot be empty") + }) +} + +func TestReplicateConfigValidator_validateClusterBasic(t *testing.T) { + t.Run("success - valid clusters", func(t *testing.T) { + clusters := []*commonpb.MilvusCluster{ + { + ClusterId: "cluster-1", + ConnectionParam: &commonpb.ConnectionParam{ + Uri: "localhost:19530", + Token: "test-token", + }, + Pchannels: []string{"cluster-1-channel-1", "cluster-1-channel-2"}, + }, + { + ClusterId: "cluster-2", + ConnectionParam: &commonpb.ConnectionParam{ + Uri: "localhost:19531", + Token: "test-token", + }, + Pchannels: []string{"cluster-2-channel-1", "cluster-2-channel-2"}, + }, + } + + validator := &ReplicateConfigValidator{ + clusterMap: make(map[string]*commonpb.MilvusCluster), + } + + err := validator.validateClusterBasic(clusters) + assert.NoError(t, err) + assert.Len(t, validator.clusterMap, 2) + assert.NotNil(t, validator.clusterMap["cluster-1"]) + assert.NotNil(t, validator.clusterMap["cluster-2"]) + }) + + t.Run("error - nil cluster", func(t *testing.T) { + clusters := []*commonpb.MilvusCluster{ + nil, + { + ClusterId: "cluster-1", + ConnectionParam: &commonpb.ConnectionParam{ + Uri: "localhost:19530", + Token: "test-token", + }, + Pchannels: []string{"cluster-1-channel-1"}, + }, + } + + validator := &ReplicateConfigValidator{ + clusterMap: make(map[string]*commonpb.MilvusCluster), + } + + err := validator.validateClusterBasic(clusters) + assert.Error(t, err) + assert.Contains(t, err.Error(), "cluster at index 0 is nil") + }) + + t.Run("error - empty cluster ID", func(t *testing.T) { + clusters := []*commonpb.MilvusCluster{ + { + ClusterId: "", + ConnectionParam: &commonpb.ConnectionParam{ + Uri: "localhost:19530", + Token: "test-token", + }, + Pchannels: []string{"channel-1"}, + }, + } + + validator := &ReplicateConfigValidator{ + clusterMap: make(map[string]*commonpb.MilvusCluster), + } + + err := validator.validateClusterBasic(clusters) + assert.Error(t, err) + assert.Contains(t, err.Error(), "has empty clusterID") + }) + + t.Run("error - cluster ID with whitespace", func(t *testing.T) { + clusters := []*commonpb.MilvusCluster{ + { + ClusterId: "cluster 1", + ConnectionParam: &commonpb.ConnectionParam{ + Uri: "localhost:19530", + Token: "test-token", + }, + Pchannels: []string{"cluster-1-channel-1"}, + }, + } + + validator := &ReplicateConfigValidator{ + clusterMap: make(map[string]*commonpb.MilvusCluster), + } + + err := validator.validateClusterBasic(clusters) + assert.Error(t, err) + assert.Contains(t, err.Error(), "containing whitespace characters") + }) + + t.Run("error - nil connection param", func(t *testing.T) { + clusters := []*commonpb.MilvusCluster{ + { + ClusterId: "cluster-1", + ConnectionParam: nil, + Pchannels: []string{"cluster-1-channel-1"}, + }, + } + + validator := &ReplicateConfigValidator{ + clusterMap: make(map[string]*commonpb.MilvusCluster), + } + + err := validator.validateClusterBasic(clusters) + assert.Error(t, err) + assert.Contains(t, err.Error(), "has nil connection_param") + }) + + t.Run("error - empty URI", func(t *testing.T) { + clusters := []*commonpb.MilvusCluster{ + { + ClusterId: "cluster-1", + ConnectionParam: &commonpb.ConnectionParam{ + Uri: "", + Token: "test-token", + }, + Pchannels: []string{"cluster-1-channel-1"}, + }, + } + + validator := &ReplicateConfigValidator{ + clusterMap: make(map[string]*commonpb.MilvusCluster), + } + + err := validator.validateClusterBasic(clusters) + assert.Error(t, err) + assert.Contains(t, err.Error(), "has empty URI") + }) + + t.Run("error - invalid URI format", func(t *testing.T) { + clusters := []*commonpb.MilvusCluster{ + { + ClusterId: "cluster-1", + ConnectionParam: &commonpb.ConnectionParam{ + Uri: "invalid-uri-format", + Token: "test-token", + }, + Pchannels: []string{"cluster-1-channel-1"}, + }, + } + + validator := &ReplicateConfigValidator{ + clusterMap: make(map[string]*commonpb.MilvusCluster), + } + + err := validator.validateClusterBasic(clusters) + assert.Error(t, err) + assert.Contains(t, err.Error(), "has invalid URI format") + }) + + t.Run("error - empty pchannels", func(t *testing.T) { + clusters := []*commonpb.MilvusCluster{ + { + ClusterId: "cluster-1", + ConnectionParam: &commonpb.ConnectionParam{ + Uri: "localhost:19530", + Token: "test-token", + }, + Pchannels: []string{}, + }, + } + + validator := &ReplicateConfigValidator{ + clusterMap: make(map[string]*commonpb.MilvusCluster), + } + + err := validator.validateClusterBasic(clusters) + assert.Error(t, err) + assert.Contains(t, err.Error(), "has empty pchannels") + }) + + t.Run("error - empty pchannel", func(t *testing.T) { + clusters := []*commonpb.MilvusCluster{ + { + ClusterId: "cluster-1", + ConnectionParam: &commonpb.ConnectionParam{ + Uri: "localhost:19530", + Token: "test-token", + }, + Pchannels: []string{"", "cluster-1-channel-2"}, + }, + } + + validator := &ReplicateConfigValidator{ + clusterMap: make(map[string]*commonpb.MilvusCluster), + } + + err := validator.validateClusterBasic(clusters) + assert.Error(t, err) + assert.Contains(t, err.Error(), "has empty pchannel at index 0") + }) + + t.Run("error - duplicate pchannel within cluster", func(t *testing.T) { + clusters := []*commonpb.MilvusCluster{ + { + ClusterId: "cluster-1", + ConnectionParam: &commonpb.ConnectionParam{ + Uri: "localhost:19530", + Token: "test-token", + }, + Pchannels: []string{"cluster-1-channel-1", "cluster-1-channel-1"}, + }, + } + + validator := &ReplicateConfigValidator{ + clusterMap: make(map[string]*commonpb.MilvusCluster), + } + + err := validator.validateClusterBasic(clusters) + assert.Error(t, err) + assert.Contains(t, err.Error(), "has duplicate pchannel") + }) + + t.Run("error - pchannel doesn't start with cluster ID", func(t *testing.T) { + clusters := []*commonpb.MilvusCluster{ + { + ClusterId: "cluster-1", + ConnectionParam: &commonpb.ConnectionParam{ + Uri: "localhost:19530", + Token: "test-token", + }, + Pchannels: []string{"wrong-prefix-channel"}, + }, + } + + validator := &ReplicateConfigValidator{ + clusterMap: make(map[string]*commonpb.MilvusCluster), + } + + err := validator.validateClusterBasic(clusters) + assert.Error(t, err) + assert.Contains(t, err.Error(), "does not start with clusterID as prefix") + }) + + t.Run("error - inconsistent pchannel count", func(t *testing.T) { + clusters := []*commonpb.MilvusCluster{ + { + ClusterId: "cluster-1", + ConnectionParam: &commonpb.ConnectionParam{ + Uri: "localhost:19530", + Token: "test-token", + }, + Pchannels: []string{"cluster-1-channel-1", "cluster-1-channel-2"}, + }, + { + ClusterId: "cluster-2", + ConnectionParam: &commonpb.ConnectionParam{ + Uri: "localhost:19531", + Token: "test-token", + }, + Pchannels: []string{"cluster-2-channel-1"}, // Only 1 channel instead of 2 + }, + } + + validator := &ReplicateConfigValidator{ + clusterMap: make(map[string]*commonpb.MilvusCluster), + } + + err := validator.validateClusterBasic(clusters) + assert.Error(t, err) + assert.Contains(t, err.Error(), "has 1 pchannels, but expected 2") + }) + + t.Run("error - duplicate cluster ID", func(t *testing.T) { + clusters := []*commonpb.MilvusCluster{ + { + ClusterId: "cluster-1", + ConnectionParam: &commonpb.ConnectionParam{ + Uri: "localhost:19530", + Token: "test-token", + }, + Pchannels: []string{"cluster-1-channel-1"}, + }, + { + ClusterId: "cluster-1", // Duplicate cluster ID + ConnectionParam: &commonpb.ConnectionParam{ + Uri: "localhost:19531", + Token: "test-token", + }, + Pchannels: []string{"cluster-1-channel-1"}, + }, + } + + validator := &ReplicateConfigValidator{ + clusterMap: make(map[string]*commonpb.MilvusCluster), + } + + err := validator.validateClusterBasic(clusters) + assert.Error(t, err) + assert.Contains(t, err.Error(), "duplicate clusterID found") + }) +} + +func TestReplicateConfigValidator_validateRelevance(t *testing.T) { + t.Run("success - current cluster included and pchannels match", func(t *testing.T) { + validator := &ReplicateConfigValidator{ + currentClusterID: "cluster-1", + currentPChannels: []string{"cluster-1-channel-1", "cluster-1-channel-2"}, + clusterMap: map[string]*commonpb.MilvusCluster{ + "cluster-1": { + ClusterId: "cluster-1", + Pchannels: []string{"cluster-1-channel-1", "cluster-1-channel-2"}, + }, + }, + } + + err := validator.validateRelevance() + assert.NoError(t, err) + }) + + t.Run("error - current cluster not included", func(t *testing.T) { + validator := &ReplicateConfigValidator{ + currentClusterID: "cluster-1", + currentPChannels: []string{"cluster-1-channel-1"}, + clusterMap: map[string]*commonpb.MilvusCluster{ + "cluster-2": { + ClusterId: "cluster-2", + Pchannels: []string{"cluster-2-channel-1"}, + }, + }, + } + + err := validator.validateRelevance() + assert.Error(t, err) + assert.Contains(t, err.Error(), "must be included in the clusters list") + }) + + t.Run("error - pchannels don't match", func(t *testing.T) { + validator := &ReplicateConfigValidator{ + currentClusterID: "cluster-1", + currentPChannels: []string{"cluster-1-channel-1", "cluster-1-channel-2"}, + clusterMap: map[string]*commonpb.MilvusCluster{ + "cluster-1": { + ClusterId: "cluster-1", + Pchannels: []string{"cluster-1-channel-1", "cluster-1-channel-3"}, // Different channels + }, + }, + } + + err := validator.validateRelevance() + assert.Error(t, err) + assert.Contains(t, err.Error(), "current pchannels do not match") + }) +} + +func TestReplicateConfigValidator_validateTopologyEdgeUniqueness(t *testing.T) { + validator := &ReplicateConfigValidator{ + clusterMap: map[string]*commonpb.MilvusCluster{ + "cluster-1": {ClusterId: "cluster-1"}, + "cluster-2": {ClusterId: "cluster-2"}, + "cluster-3": {ClusterId: "cluster-3"}, + }, + } + + t.Run("success - unique edges", func(t *testing.T) { + topologies := []*commonpb.CrossClusterTopology{ + { + SourceClusterId: "cluster-1", + TargetClusterId: "cluster-2", + }, + { + SourceClusterId: "cluster-1", + TargetClusterId: "cluster-3", + }, + } + + err := validator.validateTopologyEdgeUniqueness(topologies) + assert.NoError(t, err) + }) + + t.Run("success - empty topologies", func(t *testing.T) { + topologies := []*commonpb.CrossClusterTopology{} + + err := validator.validateTopologyEdgeUniqueness(topologies) + assert.NoError(t, err) + }) + + t.Run("error - nil topology", func(t *testing.T) { + topologies := []*commonpb.CrossClusterTopology{ + nil, + { + SourceClusterId: "cluster-1", + TargetClusterId: "cluster-2", + }, + } + + err := validator.validateTopologyEdgeUniqueness(topologies) + assert.Error(t, err) + assert.Contains(t, err.Error(), "topology at index 0 is nil") + }) + + t.Run("error - source cluster not exists", func(t *testing.T) { + topologies := []*commonpb.CrossClusterTopology{ + { + SourceClusterId: "non-existent-cluster", + TargetClusterId: "cluster-2", + }, + } + + err := validator.validateTopologyEdgeUniqueness(topologies) + assert.Error(t, err) + assert.Contains(t, err.Error(), "references non-existent source cluster") + }) + + t.Run("error - target cluster not exists", func(t *testing.T) { + topologies := []*commonpb.CrossClusterTopology{ + { + SourceClusterId: "cluster-1", + TargetClusterId: "non-existent-cluster", + }, + } + + err := validator.validateTopologyEdgeUniqueness(topologies) + assert.Error(t, err) + assert.Contains(t, err.Error(), "references non-existent target cluster") + }) + + t.Run("error - duplicate edge", func(t *testing.T) { + topologies := []*commonpb.CrossClusterTopology{ + { + SourceClusterId: "cluster-1", + TargetClusterId: "cluster-2", + }, + { + SourceClusterId: "cluster-1", + TargetClusterId: "cluster-2", // Duplicate edge + }, + } + + err := validator.validateTopologyEdgeUniqueness(topologies) + assert.Error(t, err) + assert.Contains(t, err.Error(), "duplicate topology relationship found") + }) +} + +func TestReplicateConfigValidator_validateTopologyTypeConstraint(t *testing.T) { + t.Run("success - valid star topology", func(t *testing.T) { + validator := &ReplicateConfigValidator{ + clusterMap: map[string]*commonpb.MilvusCluster{ + "center-cluster": {ClusterId: "center-cluster"}, + "leaf-cluster-1": {ClusterId: "leaf-cluster-1"}, + "leaf-cluster-2": {ClusterId: "leaf-cluster-2"}, + }, + } + + topologies := []*commonpb.CrossClusterTopology{ + { + SourceClusterId: "center-cluster", + TargetClusterId: "leaf-cluster-1", + }, + { + SourceClusterId: "center-cluster", + TargetClusterId: "leaf-cluster-2", + }, + } + + err := validator.validateTopologyTypeConstraint(topologies) + assert.NoError(t, err) + }) + + t.Run("success - empty topologies", func(t *testing.T) { + validator := &ReplicateConfigValidator{ + clusterMap: map[string]*commonpb.MilvusCluster{ + "cluster-1": {ClusterId: "cluster-1"}, + }, + } + + topologies := []*commonpb.CrossClusterTopology{} + + err := validator.validateTopologyTypeConstraint(topologies) + assert.NoError(t, err) + }) + + t.Run("error - no center node", func(t *testing.T) { + validator := &ReplicateConfigValidator{ + clusterMap: map[string]*commonpb.MilvusCluster{ + "cluster-1": {ClusterId: "cluster-1"}, + "cluster-2": {ClusterId: "cluster-2"}, + }, + } + + topologies := []*commonpb.CrossClusterTopology{ + { + SourceClusterId: "cluster-1", + TargetClusterId: "cluster-2", + }, + { + SourceClusterId: "cluster-2", + TargetClusterId: "cluster-1", + }, + } + + err := validator.validateTopologyTypeConstraint(topologies) + assert.Error(t, err) + assert.Contains(t, err.Error(), "no center node found") + }) + + t.Run("error - leaf node with wrong degrees", func(t *testing.T) { + validator := &ReplicateConfigValidator{ + clusterMap: map[string]*commonpb.MilvusCluster{ + "center-cluster": {ClusterId: "center-cluster"}, + "leaf-cluster-1": {ClusterId: "leaf-cluster-1"}, + "leaf-cluster-2": {ClusterId: "leaf-cluster-2"}, + }, + } + + topologies := []*commonpb.CrossClusterTopology{ + { + SourceClusterId: "center-cluster", + TargetClusterId: "leaf-cluster-1", + }, + { + SourceClusterId: "center-cluster", + TargetClusterId: "leaf-cluster-2", + }, + { + SourceClusterId: "leaf-cluster-1", + TargetClusterId: "leaf-cluster-2", + }, + } + + err := validator.validateTopologyTypeConstraint(topologies) + assert.Error(t, err) + assert.Contains(t, err.Error(), "does not follow star topology pattern") + }) +} + +func TestEqualIgnoreOrder(t *testing.T) { + t.Run("success - same slices in different order", func(t *testing.T) { + a := []string{"a", "b", "c"} + b := []string{"c", "a", "b"} + result := equalIgnoreOrder(a, b) + assert.True(t, result) + }) + + t.Run("success - same slices in same order", func(t *testing.T) { + a := []string{"a", "b", "c"} + b := []string{"a", "b", "c"} + result := equalIgnoreOrder(a, b) + assert.True(t, result) + }) + + t.Run("success - empty slices", func(t *testing.T) { + a := []string{} + b := []string{} + result := equalIgnoreOrder(a, b) + assert.True(t, result) + }) + + t.Run("failure - different lengths", func(t *testing.T) { + a := []string{"a", "b"} + b := []string{"a", "b", "c"} + result := equalIgnoreOrder(a, b) + assert.False(t, result) + }) + + t.Run("failure - different content", func(t *testing.T) { + a := []string{"a", "b", "c"} + b := []string{"a", "b", "d"} + result := equalIgnoreOrder(a, b) + assert.False(t, result) + }) + + t.Run("failure - different counts of same elements", func(t *testing.T) { + a := []string{"a", "a", "b"} + b := []string{"a", "b", "b"} + result := equalIgnoreOrder(a, b) + assert.False(t, result) + }) +} diff --git a/pkg/util/replicateutil/util.go b/pkg/util/replicateutil/util.go new file mode 100644 index 0000000000..7c1820f423 --- /dev/null +++ b/pkg/util/replicateutil/util.go @@ -0,0 +1,43 @@ +// Licensed to the LF AI & Data foundation under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The 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 replicateutil + +import ( + "fmt" + + "github.com/samber/lo" + "go.uber.org/zap" + + "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" +) + +func ConfigLogFields(config *commonpb.ReplicateConfiguration) []zap.Field { + fields := make([]zap.Field, 0) + fields = append(fields, zap.Int("clusterCount", len(config.GetClusters()))) + fields = append(fields, zap.Strings("clusters", lo.Map(config.GetClusters(), func(cluster *commonpb.MilvusCluster, _ int) string { + return cluster.GetClusterId() + }))) + fields = append(fields, zap.Int("topologyCount", len(config.GetCrossClusterTopology()))) + fields = append(fields, zap.Strings("topologies", lo.Map(config.GetCrossClusterTopology(), func(topology *commonpb.CrossClusterTopology, _ int) string { + return fmt.Sprintf("%s->%s", topology.GetSourceClusterId(), topology.GetTargetClusterId()) + }))) + for _, cluster := range config.GetClusters() { + fields = append(fields, zap.String("clusterInfo", fmt.Sprintf("clusterID: %s, uri: %s, pchannels: %v", + cluster.GetClusterId(), cluster.GetConnectionParam().GetUri(), cluster.GetPchannels()))) + } + return fields +} diff --git a/pkg/util/typeutil/type.go b/pkg/util/typeutil/type.go index 1a97ced330..a762fb61d3 100644 --- a/pkg/util/typeutil/type.go +++ b/pkg/util/typeutil/type.go @@ -54,6 +54,8 @@ const ( StreamingNodeRole = "streamingnode" // MixCoordRole is a constant represent MixCoord MixCoordRole = "mixcoord" + // CDCRole is a constant represent CDC + CDCRole = "cdc" ) var ( @@ -68,6 +70,7 @@ var ( DataNodeRole, StreamingNodeRole, MixCoordRole, + CDCRole, ) serverTypeList = serverTypeSet.Collect() ) diff --git a/scripts/run_go_unittest.sh b/scripts/run_go_unittest.sh index 6a9b5df0bb..1ce7b4fc3d 100755 --- a/scripts/run_go_unittest.sh +++ b/scripts/run_go_unittest.sh @@ -172,6 +172,10 @@ function test_mixcoord() { go test -gcflags="all=-N -l" -race -cover -tags dynamic,test "${MILVUS_DIR}/distributed/mixcoord/..." -failfast -count=1 -ldflags="-r ${RPATH}" } +function test_cdc() { +go test -gcflags="all=-N -l" -race -cover -tags dynamic,test "${MILVUS_DIR}/cdc/..." -failfast -count=1 -ldflags="-r ${RPATH}" +} + function test_all() { test_proxy @@ -191,6 +195,7 @@ test_metastore test_cmd test_streaming test_mixcoord +test_cdc } @@ -250,6 +255,9 @@ case "${TEST_TAG}" in mixcoord) test_mixcoord ;; + cdc) + test_cdc + ;; *) echo "Test All"; test_all ;; diff --git a/scripts/start_cluster.sh b/scripts/start_cluster.sh index 5cb3c9089e..1767c2d938 100755 --- a/scripts/start_cluster.sh +++ b/scripts/start_cluster.sh @@ -42,3 +42,6 @@ nohup ./bin/milvus run querynode --run-with-subprocess >/tmp/querynode.log 2>&1 echo "Starting streamingnode..." nohup ./bin/milvus run streamingnode --run-with-subprocess >/tmp/streamingnode.log 2>&1 & + +echo "Starting cdc..." +nohup ./bin/milvus run cdc --run-with-subprocess >/tmp/cdc.log 2>&1 & diff --git a/scripts/start_standalone.sh b/scripts/start_standalone.sh index 5d7f78f725..73534a1396 100755 --- a/scripts/start_standalone.sh +++ b/scripts/start_standalone.sh @@ -30,3 +30,6 @@ fi echo "Starting standalone..." nohup ./bin/milvus run standalone --run-with-subprocess >/tmp/standalone.log 2>&1 & + +echo "Starting cdc..." +nohup ./bin/milvus run cdc --run-with-subprocess >/tmp/cdc.log 2>&1 & diff --git a/tests/go_client/go.mod b/tests/go_client/go.mod index 13bac72e84..07774ceb15 100644 --- a/tests/go_client/go.mod +++ b/tests/go_client/go.mod @@ -51,7 +51,7 @@ require ( github.com/kr/text v0.2.0 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect - github.com/milvus-io/milvus-proto/go-api/v2 v2.6.1 // indirect + github.com/milvus-io/milvus-proto/go-api/v2 v2.6.2-0.20250901025546-3cddc9bb1357 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/opencontainers/runtime-spec v1.0.2 // indirect diff --git a/tests/go_client/go.sum b/tests/go_client/go.sum index 5db7525978..60089f0997 100644 --- a/tests/go_client/go.sum +++ b/tests/go_client/go.sum @@ -318,8 +318,8 @@ github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfr github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8= github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/milvus-io/milvus-proto/go-api/v2 v2.6.1 h1:NLoSWXvlJD8t91G3CUsooXqYnm5nfsBngztQYYT58V0= -github.com/milvus-io/milvus-proto/go-api/v2 v2.6.1/go.mod h1:/6UT4zZl6awVeXLeE7UGDWZvXj3IWkRsh3mqsn0DiAs= +github.com/milvus-io/milvus-proto/go-api/v2 v2.6.2-0.20250901025546-3cddc9bb1357 h1:OYM9ylL42FTVL5kAHOZtsOPqzXq9Pn0/H1YLfXcS/e4= +github.com/milvus-io/milvus-proto/go-api/v2 v2.6.2-0.20250901025546-3cddc9bb1357/go.mod h1:/6UT4zZl6awVeXLeE7UGDWZvXj3IWkRsh3mqsn0DiAs= github.com/milvus-io/milvus/pkg/v2 v2.0.0-20250319085209-5a6b4e56d59e h1:VCr43pG4efacDbM4au70fh8/5hNTftoWzm1iEumvDWM= github.com/milvus-io/milvus/pkg/v2 v2.0.0-20250319085209-5a6b4e56d59e/go.mod h1:37AWzxVs2NS4QUJrkcbeLUwi+4Av0h5mEdjLI62EANU= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=